MrP0wers

char_item.cpp

Oct 6th, 2025
67
0
Never
9
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 222.17 KB | None | 0 0
  1. #include "stdafx.h"
  2.  
  3. #include <stack>
  4.  
  5. #include "utils.h"
  6. #include "config.h"
  7. #include "char.h"
  8. #include "char_manager.h"
  9. #include "item_manager.h"
  10. #include "desc.h"
  11. #include "desc_client.h"
  12. #include "desc_manager.h"
  13. #include "packet.h"
  14. #include "affect.h"
  15. #include "skill.h"
  16. #include "start_position.h"
  17. #include "mob_manager.h"
  18. #include "db.h"
  19. #include "log.h"
  20. #include "vector.h"
  21. #include "buffer_manager.h"
  22. #include "questmanager.h"
  23. #include "fishing.h"
  24. #include "party.h"
  25. #include "dungeon.h"
  26. #include "refine.h"
  27. #include "unique_item.h"
  28. #include "war_map.h"
  29. #include "xmas_event.h"
  30. #include "marriage.h"
  31. #include "polymorph.h"
  32. #include "blend_item.h"
  33. #include "BattleArena.h"
  34. #include "arena.h"
  35. #include "dev_log.h"
  36. #include "pcbang.h"
  37. #include "threeway_war.h"
  38.  
  39. #include "safebox.h"
  40. #include "shop.h"
  41.  
  42. #include "../../common/VnumHelper.h"
  43. #include "DragonSoul.h"
  44. #include "buff_on_attributes.h"
  45. #include "belt_inventory_helper.h"
  46. #include "../../common/CommonDefines.h"
  47. #include "OXEvent.h"
  48. #ifdef ENABLE_SWITCHBOT
  49. #include "switchbot.h"
  50. #endif
  51.  
  52. const int ITEM_BROKEN_METIN_VNUM = 28960;
  53. #define ENABLE_BOOKS_STACKFIX
  54.  
  55. const char CHARACTER::msc_szLastChangeItemAttrFlag[] = "Item.LastChangeItemAttr";
  56. const BYTE g_aBuffOnAttrPoints[] = { POINT_ENERGY, POINT_COSTUME_ATTR_BONUS };
  57.  
  58. struct FFindStone
  59. {
  60. std::map<DWORD, LPCHARACTER> m_mapStone;
  61.  
  62. void operator()(LPENTITY pEnt)
  63. {
  64. if (pEnt->IsType(ENTITY_CHARACTER) == true)
  65. {
  66. LPCHARACTER pChar = (LPCHARACTER)pEnt;
  67.  
  68. if (pChar->IsStone() == true)
  69. {
  70. m_mapStone[(DWORD)pChar->GetVID()] = pChar;
  71. }
  72. }
  73. }
  74. };
  75.  
  76.  
  77. //귀환부, 귀환기억부, 결혼반지
  78. static bool IS_SUMMON_ITEM(int vnum)
  79. {
  80. switch (vnum)
  81. {
  82. case 22000:
  83. case 22010:
  84. case 22011:
  85. case 22020:
  86. case ITEM_MARRIAGE_RING:
  87. return true;
  88. }
  89.  
  90. return false;
  91. }
  92.  
  93. //BLOCK_DOJANG
  94. static bool IS_ENABLE_ITEM(int vnum)
  95. {
  96. switch (vnum)
  97. {
  98. case 27003:
  99. case 72726:
  100. return true;
  101. }
  102.  
  103. return false;
  104. }
  105. //END BLOCK_DOJANG
  106.  
  107. static bool IS_BLOCK_WAR_ITEMS(int vnum)
  108. {
  109. switch (vnum)
  110. {
  111. case 26005:
  112. case 26006:
  113. case 26007:
  114. case 26008:
  115. case 33433:
  116. case 33434:
  117. case 33435:
  118. case 33436:
  119. case 33437:
  120. case 33438:
  121. case 33439:
  122. case 17680:
  123. case 17681:
  124. case 17682:
  125. case 17683:
  126. case 17684:
  127. case 17685:
  128. case 17686:
  129. case 17687:
  130. case 17688:
  131. case 17689:
  132. case 17690:
  133. case 17691:
  134. case 17692:
  135. case 17693:
  136. case 17694:
  137. case 17695:
  138. case 17696:
  139. case 17697:
  140. case 17698:
  141. case 17699:
  142. case 17700:
  143. case 17701:
  144. case 17702:
  145. case 17703:
  146. case 17704:
  147. case 17705:
  148. case 18638:
  149. case 18639:
  150. case 18640:
  151. case 18641:
  152. case 18642:
  153. case 18643:
  154. case 18644:
  155. case 18645:
  156. case 18646:
  157. case 18647:
  158. case 18648:
  159. case 18649:
  160. case 18650:
  161. case 18651:
  162. case 18652:
  163. case 18653:
  164. case 18654:
  165. case 18655:
  166. case 18656:
  167. case 18657:
  168. case 21451:
  169. case 21452:
  170. case 21453:
  171. case 21454:
  172. case 21455:
  173. case 21456:
  174. case 21461:
  175. case 21462:
  176. case 21463:
  177. case 21464:
  178. case 21465:
  179. case 23481:
  180. case 23482:
  181. case 23483:
  182. case 23484:
  183. case 23485:
  184. case 23486:
  185. case 23487:
  186. case 23488:
  187. case 23489:
  188. case 23490:
  189. case 23492:
  190. case 23493:
  191. case 23494:
  192. case 23495:
  193. case 23496:
  194. case 23497:
  195. case 23498:
  196. case 23499:
  197. case 23500:
  198. case 23501:
  199. case 23502:
  200. case 23503:
  201. case 23504:
  202. case 23505:
  203. case 23506:
  204. case 23507:
  205. case 23508:
  206. case 23509:
  207. case 23510:
  208. case 23511:
  209. case 23512:
  210. case 23513:
  211. case 23514:
  212. case 23515:
  213. case 23516:
  214. case 23517:
  215. case 23518:
  216. case 23519:
  217. case 23520:
  218.  
  219. return true;
  220. }
  221.  
  222. return false;
  223. }
  224.  
  225. bool IS_ENABLE_ITEM_ZONE(int map_index)
  226. {
  227. switch (map_index)
  228. {
  229. case 112:
  230. return false;
  231. }
  232.  
  233. return true;
  234. }
  235.  
  236. bool IS_BOTARYABLE_ZONE(int nMapIndex)
  237. {
  238. if (!g_bEnableBootaryCheck) return true;
  239.  
  240. switch (nMapIndex)
  241. {
  242. case 1 :
  243. case 3 :
  244. case 21 :
  245. case 23 :
  246. case 41 :
  247. case 43 :
  248. return true;
  249. }
  250.  
  251. return false;
  252. }
  253.  
  254. // item socket 이 프로토타입과 같은지 체크 -- by mhh
  255. static bool FN_check_item_socket(LPITEM item)
  256. {
  257. for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
  258. {
  259. if (item->GetSocket(i) != item->GetProto()->alSockets[i])
  260. return false;
  261. }
  262.  
  263. return true;
  264. }
  265.  
  266. // item socket 복사 -- by mhh
  267. static void FN_copy_item_socket(LPITEM dest, LPITEM src)
  268. {
  269. for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
  270. {
  271. dest->SetSocket(i, src->GetSocket(i));
  272. }
  273. }
  274. static bool FN_check_item_sex(LPCHARACTER ch, LPITEM item)
  275. {
  276. // 남자 금지
  277. if (IS_SET(item->GetAntiFlag(), ITEM_ANTIFLAG_MALE))
  278. {
  279. if (SEX_MALE==GET_SEX(ch))
  280. return false;
  281. }
  282. // 여자금지
  283. if (IS_SET(item->GetAntiFlag(), ITEM_ANTIFLAG_FEMALE))
  284. {
  285. if (SEX_FEMALE==GET_SEX(ch))
  286. return false;
  287. }
  288.  
  289. return true;
  290. }
  291.  
  292.  
  293. /////////////////////////////////////////////////////////////////////////////
  294. // ITEM HANDLING
  295. /////////////////////////////////////////////////////////////////////////////
  296. bool CHARACTER::CanHandleItem(bool bSkipCheckRefine, bool bSkipObserver)
  297. {
  298. if (!bSkipObserver)
  299. if (m_bIsObserver)
  300. return false;
  301.  
  302. if (GetMyShop())
  303. return false;
  304.  
  305. if (!bSkipCheckRefine)
  306. if (m_bUnderRefine)
  307. return false;
  308.  
  309. if (IsCubeOpen() || NULL != DragonSoul_RefineWindow_GetOpener())
  310. return false;
  311.  
  312. if (IsWarping())
  313. return false;
  314.  
  315. #ifdef __CHANGELOOK_SYSTEM__
  316. if (m_bChangeLook)
  317. return false;
  318. #endif
  319.  
  320. return true;
  321. }
  322.  
  323. LPITEM CHARACTER::GetInventoryItem(WORD wCell) const
  324. {
  325. return GetItem(TItemPos(INVENTORY, wCell));
  326. }
  327. LPITEM CHARACTER::GetItem(TItemPos Cell) const
  328. {
  329. if (!IsValidItemPosition(Cell))
  330. return NULL;
  331. WORD wCell = Cell.cell;
  332. BYTE window_type = Cell.window_type;
  333. switch (window_type)
  334. {
  335. case INVENTORY:
  336. case EQUIPMENT:
  337. if (wCell >= INVENTORY_AND_EQUIP_SLOT_MAX)
  338. {
  339. sys_err("CHARACTER::GetInventoryItem: invalid item cell %d", wCell);
  340. return NULL;
  341. }
  342. return m_pointsInstant.pItems[wCell];
  343. case DRAGON_SOUL_INVENTORY:
  344. if (wCell >= DRAGON_SOUL_INVENTORY_MAX_NUM)
  345. {
  346. sys_err("CHARACTER::GetInventoryItem: invalid DS item cell %d", wCell);
  347. return NULL;
  348. }
  349. return m_pointsInstant.pDSItems[wCell];
  350. #ifdef ENABLE_SWITCHBOT
  351. case SWITCHBOT:
  352. if (wCell >= SWITCHBOT_SLOT_COUNT)
  353. {
  354. sys_err("CHARACTER::GetInventoryItem: invalid switchbot item cell %d", wCell);
  355. return NULL;
  356. }
  357. return m_pointsInstant.pSwitchbotItems[wCell];
  358. #endif
  359. default:
  360. return NULL;
  361. }
  362. return NULL;
  363. }
  364.  
  365. void CHARACTER::SetItem(TItemPos Cell, LPITEM pItem)
  366. {
  367. WORD wCell = Cell.cell;
  368. BYTE window_type = Cell.window_type;
  369. if ((unsigned long)((CItem*)pItem) == 0xff || (unsigned long)((CItem*)pItem) == 0xffffffff)
  370. {
  371. sys_err("!!! FATAL ERROR !!! item == 0xff (char: %s cell: %u)", GetStringName().c_str(), wCell);
  372. core_dump();
  373. return;
  374. }
  375.  
  376. if (pItem && pItem->GetOwner())
  377. {
  378. assert(!"GetOwner exist");
  379. return;
  380. }
  381.  
  382. switch(window_type)
  383. {
  384. case INVENTORY:
  385. case EQUIPMENT:
  386. {
  387. if (wCell >= INVENTORY_AND_EQUIP_SLOT_MAX)
  388. {
  389. sys_err("CHARACTER::SetItem: invalid item cell %d", wCell);
  390. return;
  391. }
  392.  
  393. LPITEM pOld = m_pointsInstant.pItems[wCell];
  394.  
  395. if (pOld)
  396. {
  397. if (wCell < INVENTORY_MAX_NUM)
  398. {
  399. for (int i = 0; i < pOld->GetSize(); ++i)
  400. {
  401. int p = wCell + (i * 5);
  402.  
  403. if (p >= INVENTORY_MAX_NUM)
  404. continue;
  405.  
  406. if (m_pointsInstant.pItems[p] && m_pointsInstant.pItems[p] != pOld)
  407. continue;
  408.  
  409. m_pointsInstant.bItemGrid[p] = 0;
  410. }
  411. }
  412. else
  413. m_pointsInstant.bItemGrid[wCell] = 0;
  414. }
  415.  
  416. if (pItem)
  417. {
  418. if (wCell < INVENTORY_MAX_NUM)
  419. {
  420. for (int i = 0; i < pItem->GetSize(); ++i)
  421. {
  422. int p = wCell + (i * 5);
  423.  
  424. if (p >= INVENTORY_MAX_NUM)
  425. continue;
  426.  
  427. m_pointsInstant.bItemGrid[p] = wCell + 1;
  428. }
  429. }
  430. else
  431. m_pointsInstant.bItemGrid[wCell] = wCell + 1;
  432. }
  433.  
  434. m_pointsInstant.pItems[wCell] = pItem;
  435. }
  436. break;
  437. case DRAGON_SOUL_INVENTORY:
  438. {
  439. LPITEM pOld = m_pointsInstant.pDSItems[wCell];
  440.  
  441. if (pOld)
  442. {
  443. if (wCell < DRAGON_SOUL_INVENTORY_MAX_NUM)
  444. {
  445. for (int i = 0; i < pOld->GetSize(); ++i)
  446. {
  447. int p = wCell + (i * DRAGON_SOUL_BOX_COLUMN_NUM);
  448.  
  449. if (p >= DRAGON_SOUL_INVENTORY_MAX_NUM)
  450. continue;
  451.  
  452. if (m_pointsInstant.pDSItems[p] && m_pointsInstant.pDSItems[p] != pOld)
  453. continue;
  454.  
  455. m_pointsInstant.wDSItemGrid[p] = 0;
  456. }
  457. }
  458. else
  459. m_pointsInstant.wDSItemGrid[wCell] = 0;
  460. }
  461.  
  462. if (pItem)
  463. {
  464. if (wCell >= DRAGON_SOUL_INVENTORY_MAX_NUM)
  465. {
  466. sys_err("CHARACTER::SetItem: invalid DS item cell %d", wCell);
  467. return;
  468. }
  469.  
  470. if (wCell < DRAGON_SOUL_INVENTORY_MAX_NUM)
  471. {
  472. for (int i = 0; i < pItem->GetSize(); ++i)
  473. {
  474. int p = wCell + (i * DRAGON_SOUL_BOX_COLUMN_NUM);
  475.  
  476. if (p >= DRAGON_SOUL_INVENTORY_MAX_NUM)
  477. continue;
  478.  
  479. m_pointsInstant.wDSItemGrid[p] = wCell + 1;
  480. }
  481. }
  482. else
  483. m_pointsInstant.wDSItemGrid[wCell] = wCell + 1;
  484. }
  485.  
  486. m_pointsInstant.pDSItems[wCell] = pItem;
  487. }
  488. break;
  489. #ifdef ENABLE_SWITCHBOT
  490. case SWITCHBOT:
  491. {
  492. LPITEM pOld = m_pointsInstant.pSwitchbotItems[wCell];
  493. if (pItem && pOld)
  494. {
  495. return;
  496. }
  497.  
  498. if (wCell >= SWITCHBOT_SLOT_COUNT)
  499. {
  500. sys_err("CHARACTER::SetItem: invalid switchbot item cell %d", wCell);
  501. return;
  502. }
  503.  
  504. if (pItem)
  505. {
  506. CSwitchbotManager::Instance().RegisterItem(GetPlayerID(), pItem->GetID(), wCell);
  507. }
  508. else
  509. {
  510. CSwitchbotManager::Instance().UnregisterItem(GetPlayerID(), wCell);
  511. }
  512.  
  513. m_pointsInstant.pSwitchbotItems[wCell] = pItem;
  514. }
  515. break;
  516. #endif
  517. default:
  518. sys_err ("Invalid Inventory type %d", window_type);
  519. return;
  520. }
  521.  
  522. if (GetDesc())
  523. {
  524. if (pItem)
  525. {
  526. TPacketGCItemSet pack;
  527. pack.header = HEADER_GC_ITEM_SET;
  528. pack.Cell = Cell;
  529.  
  530. pack.count = pItem->GetCount();
  531. #ifdef __CHANGELOOK_SYSTEM__
  532. pack.transmutation = pItem->GetTransmutation();
  533. #endif
  534. #ifdef ENABLE_AUTODESC_SYSTEM
  535. strlcpy(pack.desc, pItem->GetDescription(), sizeof(pack.desc));
  536. #endif
  537. #ifdef ENABLE_SPECULAR_SYSTEM
  538. memcpy(pack.bSpecularColor, pItem->GetSpecularColor(), sizeof(pack.bSpecularColor));
  539. #endif
  540. pack.vnum = pItem->GetVnum();
  541. pack.flags = pItem->GetFlag();
  542. pack.anti_flags = pItem->GetAntiFlag();
  543. pack.highlight = (Cell.window_type == DRAGON_SOUL_INVENTORY);
  544.  
  545. thecore_memcpy(pack.alSockets, pItem->GetSockets(), sizeof(pack.alSockets));
  546. thecore_memcpy(pack.aAttr, pItem->GetAttributes(), sizeof(pack.aAttr));
  547.  
  548. GetDesc()->Packet(&pack, sizeof(TPacketGCItemSet));
  549. }
  550. else
  551. {
  552. TPacketGCItemDelDeprecated pack;
  553. pack.header = HEADER_GC_ITEM_DEL;
  554. pack.Cell = Cell;
  555. pack.count = 0;
  556. #ifdef __CHANGELOOK_SYSTEM__
  557. pack.transmutation = 0;
  558. #endif
  559. #ifdef ENABLE_AUTODESC_SYSTEM
  560. strlcpy(pack.desc, "NoDesc", sizeof(pack.desc));
  561. #endif
  562. #ifdef ENABLE_SPECULAR_SYSTEM
  563. memset(pack.bSpecularColor, 0, sizeof(pack.bSpecularColor));
  564. #endif
  565. pack.vnum = 0;
  566. memset(pack.alSockets, 0, sizeof(pack.alSockets));
  567. memset(pack.aAttr, 0, sizeof(pack.aAttr));
  568.  
  569. GetDesc()->Packet(&pack, sizeof(TPacketGCItemDelDeprecated));
  570. }
  571. }
  572.  
  573. if (pItem)
  574. {
  575. pItem->SetCell(this, wCell);
  576. switch (window_type)
  577. {
  578. case INVENTORY:
  579. case EQUIPMENT:
  580. if ((wCell < INVENTORY_MAX_NUM) || (BELT_INVENTORY_SLOT_START <= wCell && BELT_INVENTORY_SLOT_END > wCell))
  581. pItem->SetWindow(INVENTORY);
  582. else
  583. pItem->SetWindow(EQUIPMENT);
  584. break;
  585. case DRAGON_SOUL_INVENTORY:
  586. pItem->SetWindow(DRAGON_SOUL_INVENTORY);
  587. break;
  588. #ifdef ENABLE_SWITCHBOT
  589. case SWITCHBOT:
  590. pItem->SetWindow(SWITCHBOT);
  591. break;
  592. #endif
  593. }
  594. }
  595. }
  596.  
  597. LPITEM CHARACTER::GetWear(BYTE bCell) const
  598. {
  599. if (bCell >= WEAR_MAX_NUM + DRAGON_SOUL_DECK_MAX_NUM * DS_SLOT_MAX)
  600. {
  601. sys_err("CHARACTER::GetWear: invalid wear cell %d", bCell);
  602. return NULL;
  603. }
  604.  
  605. return m_pointsInstant.pItems[INVENTORY_MAX_NUM + bCell];
  606. }
  607.  
  608. void CHARACTER::SetWear(BYTE bCell, LPITEM item)
  609. {
  610. if (bCell >= WEAR_MAX_NUM + DRAGON_SOUL_DECK_MAX_NUM * DS_SLOT_MAX)
  611. {
  612. sys_err("CHARACTER::SetItem: invalid item cell %d", bCell);
  613. return;
  614. }
  615.  
  616. SetItem(TItemPos (INVENTORY, INVENTORY_MAX_NUM + bCell), item);
  617.  
  618. if (!item && bCell == WEAR_WEAPON)
  619. {
  620. if (IsAffectFlag(AFF_GWIGUM))
  621. RemoveAffect(SKILL_GWIGEOM);
  622.  
  623. if (IsAffectFlag(AFF_GEOMGYEONG))
  624. RemoveAffect(SKILL_GEOMKYUNG);
  625. }
  626. }
  627.  
  628. void CHARACTER::ClearItem()
  629. {
  630. int i;
  631. LPITEM item;
  632.  
  633. for (i = 0; i < INVENTORY_AND_EQUIP_SLOT_MAX; ++i)
  634. {
  635. if ((item = GetInventoryItem(i)))
  636. {
  637. item->SetSkipSave(true);
  638. ITEM_MANAGER::instance().FlushDelayedSave(item);
  639.  
  640. item->RemoveFromCharacter();
  641. M2_DESTROY_ITEM(item);
  642.  
  643. SyncQuickslot(QUICKSLOT_TYPE_ITEM, i, 255);
  644. }
  645. }
  646. for (i = 0; i < DRAGON_SOUL_INVENTORY_MAX_NUM; ++i)
  647. {
  648. if ((item = GetItem(TItemPos(DRAGON_SOUL_INVENTORY, i))))
  649. {
  650. item->SetSkipSave(true);
  651. ITEM_MANAGER::instance().FlushDelayedSave(item);
  652.  
  653. item->RemoveFromCharacter();
  654. M2_DESTROY_ITEM(item);
  655. }
  656. }
  657. #ifdef ENABLE_SWITCHBOT
  658. for (i = 0; i < SWITCHBOT_SLOT_COUNT; ++i)
  659. {
  660. if ((item = GetItem(TItemPos(SWITCHBOT, i))))
  661. {
  662. item->SetSkipSave(true);
  663. ITEM_MANAGER::instance().FlushDelayedSave(item);
  664.  
  665. item->RemoveFromCharacter();
  666. M2_DESTROY_ITEM(item);
  667. }
  668. }
  669. #endif
  670. }
  671.  
  672. bool CHARACTER::IsEmptyItemGrid(TItemPos Cell, BYTE bSize, int iExceptionCell) const
  673. {
  674. switch (Cell.window_type)
  675. {
  676. case INVENTORY:
  677. {
  678. BYTE bCell = Cell.cell;
  679.  
  680. ++iExceptionCell;
  681.  
  682. if (Cell.IsBeltInventoryPosition())
  683. {
  684. LPITEM beltItem = GetWear(WEAR_BELT);
  685.  
  686. if (NULL == beltItem)
  687. return false;
  688.  
  689. if (false == CBeltInventoryHelper::IsAvailableCell(bCell - BELT_INVENTORY_SLOT_START, beltItem->GetValue(0)))
  690. return false;
  691.  
  692. if (m_pointsInstant.bItemGrid[bCell])
  693. {
  694. if (m_pointsInstant.bItemGrid[bCell] == iExceptionCell)
  695. return true;
  696.  
  697. return false;
  698. }
  699.  
  700. if (bSize == 1)
  701. return true;
  702.  
  703. }
  704. else if (bCell >= INVENTORY_MAX_NUM)
  705. return false;
  706.  
  707. if (m_pointsInstant.bItemGrid[bCell])
  708. {
  709. if (m_pointsInstant.bItemGrid[bCell] == iExceptionCell)
  710. {
  711. if (bSize == 1)
  712. return true;
  713.  
  714. int j = 1;
  715. BYTE bPage = bCell / (INVENTORY_MAX_NUM / 4);
  716.  
  717. do
  718. {
  719. BYTE p = bCell + (5 * j);
  720.  
  721. if (p >= INVENTORY_MAX_NUM)
  722. return false;
  723.  
  724. if (p / (INVENTORY_MAX_NUM / 4) != bPage)
  725. return false;
  726.  
  727. if (m_pointsInstant.bItemGrid[p])
  728. if (m_pointsInstant.bItemGrid[p] != iExceptionCell)
  729. return false;
  730. }
  731. while (++j < bSize);
  732.  
  733. return true;
  734. }
  735. else
  736. return false;
  737. }
  738.  
  739. // 크기가 1이면 한칸을 차지하는 것이므로 그냥 리턴
  740. if (1 == bSize)
  741. return true;
  742. else
  743. {
  744. int j = 1;
  745. BYTE bPage = bCell / (INVENTORY_MAX_NUM / 4);
  746.  
  747. do
  748. {
  749. BYTE p = bCell + (5 * j);
  750.  
  751. if (p >= INVENTORY_MAX_NUM)
  752. return false;
  753.  
  754. if (p / (INVENTORY_MAX_NUM / 4) != bPage)
  755. return false;
  756.  
  757. if (m_pointsInstant.bItemGrid[p])
  758. if (m_pointsInstant.bItemGrid[p] != iExceptionCell)
  759. return false;
  760. }
  761. while (++j < bSize);
  762.  
  763. return true;
  764. }
  765. }
  766. break;
  767. case DRAGON_SOUL_INVENTORY:
  768. {
  769. WORD wCell = Cell.cell;
  770. if (wCell >= DRAGON_SOUL_INVENTORY_MAX_NUM)
  771. return false;
  772.  
  773. // bItemCell은 0이 false임을 나타내기 위해 + 1 해서 처리한다.
  774. // 따라서 iExceptionCell에 1을 더해 비교한다.
  775. iExceptionCell++;
  776.  
  777. if (m_pointsInstant.wDSItemGrid[wCell])
  778. {
  779. if (m_pointsInstant.wDSItemGrid[wCell] == iExceptionCell)
  780. {
  781. if (bSize == 1)
  782. return true;
  783.  
  784. int j = 1;
  785.  
  786. do
  787. {
  788. int p = wCell + (DRAGON_SOUL_BOX_COLUMN_NUM * j);
  789.  
  790. if (p >= DRAGON_SOUL_INVENTORY_MAX_NUM)
  791. return false;
  792.  
  793. if (m_pointsInstant.wDSItemGrid[p])
  794. if (m_pointsInstant.wDSItemGrid[p] != iExceptionCell)
  795. return false;
  796. }
  797. while (++j < bSize);
  798.  
  799. return true;
  800. }
  801. else
  802. return false;
  803. }
  804.  
  805. // 크기가 1이면 한칸을 차지하는 것이므로 그냥 리턴
  806. if (1 == bSize)
  807. return true;
  808. else
  809. {
  810. int j = 1;
  811.  
  812. do
  813. {
  814. int p = wCell + (DRAGON_SOUL_BOX_COLUMN_NUM * j);
  815.  
  816. if (p >= DRAGON_SOUL_INVENTORY_MAX_NUM)
  817. return false;
  818.  
  819. if (m_pointsInstant.bItemGrid[p])
  820. if (m_pointsInstant.wDSItemGrid[p] != iExceptionCell)
  821. return false;
  822. }
  823. while (++j < bSize);
  824.  
  825. return true;
  826. }
  827. }
  828. break;
  829. #ifdef ENABLE_SWITCHBOT
  830. case SWITCHBOT:
  831. {
  832. WORD wCell = Cell.cell;
  833. if (wCell >= SWITCHBOT_SLOT_COUNT)
  834. {
  835. return false;
  836. }
  837.  
  838. if (m_pointsInstant.pSwitchbotItems[wCell])
  839. {
  840. return false;
  841. }
  842.  
  843. return true;
  844. }
  845. break;
  846. #endif
  847. }
  848. return false;
  849. }
  850.  
  851. int CHARACTER::GetEmptyInventory(BYTE size) const
  852. {
  853. for ( int i = 0; i < INVENTORY_MAX_NUM; ++i)
  854. if (IsEmptyItemGrid(TItemPos (INVENTORY, i), size))
  855. return i;
  856. return -1;
  857. }
  858.  
  859. int CHARACTER::GetEmptyDragonSoulInventory(LPITEM pItem) const
  860. {
  861. if (NULL == pItem || !pItem->IsDragonSoul())
  862. return -1;
  863. if (!DragonSoul_IsQualified())
  864. {
  865. return -1;
  866. }
  867. BYTE bSize = pItem->GetSize();
  868. WORD wBaseCell = DSManager::instance().GetBasePosition(pItem);
  869.  
  870. if (WORD_MAX == wBaseCell)
  871. return -1;
  872.  
  873. for (int i = 0; i < DRAGON_SOUL_BOX_SIZE; ++i)
  874. if (IsEmptyItemGrid(TItemPos(DRAGON_SOUL_INVENTORY, i + wBaseCell), bSize))
  875. return i + wBaseCell;
  876.  
  877. return -1;
  878. }
  879.  
  880. bool CHARACTER::IsEmptyItemGridSpecial(const TItemPos &Cell, BYTE bSize, int iExceptionCell, std::vector<WORD>& vec) const
  881. {
  882.  
  883. if (std::find(vec.begin(), vec.end(), Cell.cell) != vec.end()) {
  884. return false;
  885. }
  886.  
  887. switch (Cell.window_type)
  888. {
  889. case INVENTORY:
  890. {
  891. WORD bCell = (WORD)Cell.cell;
  892.  
  893. ++iExceptionCell;
  894.  
  895. if (Cell.IsBeltInventoryPosition())
  896. {
  897. LPITEM beltItem = GetWear(WEAR_BELT);
  898.  
  899. if (NULL == beltItem)
  900. return false;
  901.  
  902. if (false == CBeltInventoryHelper::IsAvailableCell(bCell - BELT_INVENTORY_SLOT_START, beltItem->GetValue(0)))
  903. return false;
  904.  
  905. if (m_pointsInstant.bItemGrid[bCell])
  906. {
  907. if (m_pointsInstant.bItemGrid[bCell] == iExceptionCell)
  908. return true;
  909.  
  910. return false;
  911. }
  912.  
  913. if (bSize == 1)
  914. return true;
  915.  
  916. }
  917. else if (bCell >= INVENTORY_MAX_NUM)
  918. return false;
  919.  
  920. if (m_pointsInstant.bItemGrid[bCell])
  921. {
  922. if (m_pointsInstant.bItemGrid[bCell] == iExceptionCell)
  923. {
  924. if (bSize == 1)
  925. return true;
  926.  
  927. int j = 1;
  928. WORD bPage = bCell / (INVENTORY_PAGE_SIZE);
  929.  
  930. do
  931. {
  932. WORD p = bCell + (5 * j);
  933.  
  934. if (p >= INVENTORY_MAX_NUM)
  935. return false;
  936.  
  937. if (p / (INVENTORY_PAGE_SIZE) != bPage)
  938. return false;
  939.  
  940. if (m_pointsInstant.bItemGrid[p])
  941. if (m_pointsInstant.bItemGrid[p] != iExceptionCell)
  942. return false;
  943. } while (++j < bSize);
  944.  
  945. return true;
  946. }
  947. else
  948. return false;
  949. }
  950.  
  951. if (1 == bSize)
  952. return true;
  953. else
  954. {
  955. int j = 1;
  956. WORD bPage = bCell / (INVENTORY_PAGE_SIZE);
  957.  
  958. do
  959. {
  960. WORD p = bCell + (5 * j);
  961.  
  962. if (p >= INVENTORY_MAX_NUM)
  963. return false;
  964.  
  965. if (p / (INVENTORY_PAGE_SIZE) != bPage)
  966. return false;
  967.  
  968. if (m_pointsInstant.bItemGrid[p])
  969. if (m_pointsInstant.bItemGrid[p] != iExceptionCell)
  970. return false;
  971. } while (++j < bSize);
  972.  
  973. return true;
  974. }
  975. }
  976. break;
  977. case DRAGON_SOUL_INVENTORY:
  978. {
  979. WORD wCell = Cell.cell;
  980. if (wCell >= DRAGON_SOUL_INVENTORY_MAX_NUM)
  981. return false;
  982.  
  983. iExceptionCell++;
  984.  
  985. if (m_pointsInstant.wDSItemGrid[wCell])
  986. {
  987. if (m_pointsInstant.wDSItemGrid[wCell] == iExceptionCell)
  988. {
  989. if (bSize == 1)
  990. return true;
  991.  
  992. int j = 1;
  993.  
  994. do
  995. {
  996. WORD p = wCell + (DRAGON_SOUL_BOX_COLUMN_NUM * j);
  997.  
  998. if (p >= DRAGON_SOUL_INVENTORY_MAX_NUM)
  999. return false;
  1000.  
  1001. if (m_pointsInstant.wDSItemGrid[p])
  1002. if (m_pointsInstant.wDSItemGrid[p] != iExceptionCell)
  1003. return false;
  1004. } while (++j < bSize);
  1005.  
  1006. return true;
  1007. }
  1008. else
  1009. return false;
  1010. }
  1011.  
  1012. if (1 == bSize)
  1013. return true;
  1014. else
  1015. {
  1016. int j = 1;
  1017.  
  1018. do
  1019. {
  1020. WORD p = wCell + (DRAGON_SOUL_BOX_COLUMN_NUM * j);
  1021.  
  1022. if (p >= DRAGON_SOUL_INVENTORY_MAX_NUM)
  1023. return false;
  1024.  
  1025. if (m_pointsInstant.bItemGrid[p])
  1026. if (m_pointsInstant.wDSItemGrid[p] != iExceptionCell)
  1027. return false;
  1028. } while (++j < bSize);
  1029.  
  1030. return true;
  1031. }
  1032. }
  1033. }
  1034. return false;
  1035. }
  1036.  
  1037. int CHARACTER::GetEmptyDragonSoulInventoryWithExceptions(LPITEM pItem, std::vector<WORD>& vec /*= -1*/) const
  1038. {
  1039. if (NULL == pItem || !pItem->IsDragonSoul())
  1040. return -1;
  1041. if (!DragonSoul_IsQualified())
  1042. {
  1043. return -1;
  1044. }
  1045. BYTE bSize = pItem->GetSize();
  1046. WORD wBaseCell = DSManager::instance().GetBasePosition(pItem);
  1047.  
  1048. if (WORD_MAX == wBaseCell)
  1049. return -1;
  1050.  
  1051. for (int i = 0; i < DRAGON_SOUL_BOX_SIZE; ++i)
  1052. if (IsEmptyItemGridSpecial(TItemPos(DRAGON_SOUL_INVENTORY, i + wBaseCell), bSize, -1, vec))
  1053. return i + wBaseCell;
  1054.  
  1055. return -1;
  1056. }
  1057.  
  1058. void CHARACTER::CopyDragonSoulItemGrid(std::vector<WORD>& vDragonSoulItemGrid) const
  1059. {
  1060. vDragonSoulItemGrid.resize(DRAGON_SOUL_INVENTORY_MAX_NUM);
  1061.  
  1062. std::copy(m_pointsInstant.wDSItemGrid, m_pointsInstant.wDSItemGrid + DRAGON_SOUL_INVENTORY_MAX_NUM, vDragonSoulItemGrid.begin());
  1063. }
  1064.  
  1065. int CHARACTER::CountEmptyInventory() const
  1066. {
  1067. int count = 0;
  1068.  
  1069. for (int i = 0; i < INVENTORY_MAX_NUM; ++i)
  1070. if (GetInventoryItem(i))
  1071. count += GetInventoryItem(i)->GetSize();
  1072.  
  1073. return (INVENTORY_MAX_NUM - count);
  1074. }
  1075.  
  1076. void TransformRefineItem(LPITEM pkOldItem, LPITEM pkNewItem)
  1077. {
  1078. // ACCESSORY_REFINE
  1079. if (pkOldItem->IsAccessoryForSocket())
  1080. {
  1081. for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
  1082. {
  1083. pkNewItem->SetSocket(i, pkOldItem->GetSocket(i));
  1084. }
  1085. //pkNewItem->StartAccessorySocketExpireEvent();
  1086. }
  1087. // END_OF_ACCESSORY_REFINE
  1088. else
  1089. {
  1090. // 여기서 깨진석이 자동적으로 청소 됨
  1091. for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
  1092. {
  1093. if (!pkOldItem->GetSocket(i))
  1094. break;
  1095. else
  1096. pkNewItem->SetSocket(i, 1);
  1097. }
  1098.  
  1099. // 소켓 설정
  1100. int slot = 0;
  1101.  
  1102. for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
  1103. {
  1104. long socket = pkOldItem->GetSocket(i);
  1105.  
  1106. if (socket > 2 && socket != ITEM_BROKEN_METIN_VNUM)
  1107. pkNewItem->SetSocket(slot++, socket);
  1108. }
  1109.  
  1110. }
  1111.  
  1112. // 매직 아이템 설정
  1113. pkOldItem->CopyAttributeTo(pkNewItem);
  1114. }
  1115.  
  1116. void NotifyRefineSuccess(LPCHARACTER ch, LPITEM item, const char* way)
  1117. {
  1118. if (NULL != ch && item != NULL)
  1119. {
  1120. ch->ChatPacket(CHAT_TYPE_COMMAND, "RefineSuceeded");
  1121.  
  1122. LogManager::instance().RefineLog(ch->GetPlayerID(), item->GetLocaleName(ch), item->GetID(), item->GetRefineLevel(), 1, way);
  1123. }
  1124. }
  1125.  
  1126. void NotifyRefineFail(LPCHARACTER ch, LPITEM item, const char* way, int success = 0)
  1127. {
  1128. if (NULL != ch && NULL != item)
  1129. {
  1130. ch->ChatPacket(CHAT_TYPE_COMMAND, "RefineFailed");
  1131.  
  1132. LogManager::instance().RefineLog(ch->GetPlayerID(), item->GetLocaleName(ch), item->GetID(), item->GetRefineLevel(), success, way);
  1133. }
  1134. }
  1135.  
  1136. void CHARACTER::SetRefineNPC(LPCHARACTER ch)
  1137. {
  1138. if ( ch != NULL )
  1139. {
  1140. m_dwRefineNPCVID = ch->GetVID();
  1141. }
  1142. else
  1143. {
  1144. m_dwRefineNPCVID = 0;
  1145. }
  1146. }
  1147.  
  1148. bool CHARACTER::DoRefine(LPITEM item, bool bMoneyOnly)
  1149. {
  1150. if (!CanHandleItem(true))
  1151. {
  1152. ClearRefineMode();
  1153. return false;
  1154. }
  1155. //개량 시간제한 : upgrade_refine_scroll.quest 에서 개량후 5분이내에 일반 개량을
  1156. //진행할수 없음
  1157. if (quest::CQuestManager::instance().GetEventFlag("update_refine_time") != 0)
  1158. {
  1159. if (get_global_time() < quest::CQuestManager::instance().GetEventFlag("update_refine_time") + (60 * 5))
  1160. {
  1161. sys_log(0, "can't refine %d %s", GetPlayerID(), GetStringName().c_str());
  1162. return false;
  1163. }
  1164. }
  1165.  
  1166. const TRefineTable * prt = CRefineManager::instance().GetRefineRecipe(item->GetRefineSet());
  1167.  
  1168. if (!prt)
  1169. return false;
  1170.  
  1171. DWORD result_vnum = item->GetRefinedVnum();
  1172.  
  1173. // REFINE_COST
  1174. int cost = ComputeRefineFee(prt->cost);
  1175.  
  1176. int RefineChance = GetQuestFlag("main_quest_lv7.refine_chance");
  1177.  
  1178. if (RefineChance > 0)
  1179. {
  1180. if (!item->CheckItemUseLevel(20) || item->GetType() != ITEM_WEAPON)
  1181. {
  1182. ChatInfoTrans(("무료 개량 기회는 20 이하의 무기만 가능합니다"));
  1183. return false;
  1184. }
  1185.  
  1186. cost = 0;
  1187. SetQuestFlag("main_quest_lv7.refine_chance", RefineChance - 1);
  1188. }
  1189. // END_OF_REFINE_COST
  1190.  
  1191. if (result_vnum == 0)
  1192. {
  1193. ChatInfoTrans(("더 이상 개량할 수 없습니다."));
  1194. return false;
  1195. }
  1196.  
  1197. if (item->GetType() == ITEM_USE && item->GetSubType() == USE_TUNING)
  1198. return false;
  1199.  
  1200. TItemTable * pProto = ITEM_MANAGER::instance().GetTable(item->GetRefinedVnum());
  1201.  
  1202. if (!pProto)
  1203. {
  1204. sys_err("DoRefine NOT GET ITEM PROTO %d", item->GetRefinedVnum());
  1205. ChatInfoTrans(("이 아이템은 개량할 수 없습니다."));
  1206. return false;
  1207. }
  1208.  
  1209. // REFINE_COST
  1210. if (GetGold() < cost)
  1211. {
  1212. ChatInfoTrans(("개량을 하기 위한 돈이 부족합니다."));
  1213. return false;
  1214. }
  1215.  
  1216. if (!bMoneyOnly && !RefineChance)
  1217. {
  1218. for (int i = 0; i < prt->material_count; ++i)
  1219. {
  1220. if (CountSpecifyItem(prt->materials[i].vnum) < prt->materials[i].count)
  1221. {
  1222. if (test_server)
  1223. {
  1224. ChatPacket(CHAT_TYPE_INFO, "Find %d, count %d, require %d", prt->materials[i].vnum, CountSpecifyItem(prt->materials[i].vnum), prt->materials[i].count);
  1225. }
  1226. ChatInfoTrans(("개량을 하기 위한 재료가 부족합니다."));
  1227. return false;
  1228. }
  1229. }
  1230.  
  1231. for (int i = 0; i < prt->material_count; ++i)
  1232. RemoveSpecifyItem(prt->materials[i].vnum, prt->materials[i].count);
  1233. }
  1234.  
  1235. int prob = number(1, 100);
  1236.  
  1237. if (IsRefineThroughGuild() || bMoneyOnly)
  1238. prob -= 10;
  1239.  
  1240. // END_OF_REFINE_COST
  1241.  
  1242. if (prob <= prt->prob)
  1243. {
  1244. // 성공! 모든 아이템이 사라지고, 같은 속성의 다른 아이템 획득
  1245. LPITEM pkNewItem = ITEM_MANAGER::instance().CreateItem(result_vnum, 1, 0, false);
  1246.  
  1247. if (pkNewItem)
  1248. {
  1249. ITEM_MANAGER::CopyAllAttrTo(item, pkNewItem);
  1250. LogManager::instance().ItemLog(this, pkNewItem, "REFINE SUCCESS", pkNewItem->GetLocaleName(this));
  1251.  
  1252. BYTE bCell = item->GetCell();
  1253.  
  1254. // DETAIL_REFINE_LOG
  1255. NotifyRefineSuccess(this, item, IsRefineThroughGuild() ? "GUILD" : "POWER");
  1256. DBManager::instance().SendMoneyLog(MONEY_LOG_REFINE, item->GetVnum(), -cost);
  1257. ITEM_MANAGER::instance().RemoveItem(item, "REMOVE (REFINE SUCCESS)");
  1258. // END_OF_DETAIL_REFINE_LOG
  1259.  
  1260. pkNewItem->AddToCharacter(this, TItemPos(INVENTORY, bCell));
  1261. ITEM_MANAGER::instance().FlushDelayedSave(pkNewItem);
  1262.  
  1263. sys_log(0, "Refine Success %d", cost);
  1264. pkNewItem->AttrLog();
  1265. //PointChange(POINT_GOLD, -cost);
  1266. sys_log(0, "PayPee %d", cost);
  1267. PayRefineFee(cost);
  1268. sys_log(0, "PayPee End %d", cost);
  1269. }
  1270. else
  1271. {
  1272. // DETAIL_REFINE_LOG
  1273. // 아이템 생성에 실패 -> 개량 실패로 간주
  1274. sys_err("cannot create item %u", result_vnum);
  1275. NotifyRefineFail(this, item, IsRefineThroughGuild() ? "GUILD" : "POWER");
  1276. // END_OF_DETAIL_REFINE_LOG
  1277. }
  1278. }
  1279. else
  1280. {
  1281. // 실패! 모든 아이템이 사라짐.
  1282. DBManager::instance().SendMoneyLog(MONEY_LOG_REFINE, item->GetVnum(), -cost);
  1283. NotifyRefineFail(this, item, IsRefineThroughGuild() ? "GUILD" : "POWER");
  1284. item->AttrLog();
  1285. ITEM_MANAGER::instance().RemoveItem(item, "REMOVE (REFINE FAIL)");
  1286.  
  1287. //PointChange(POINT_GOLD, -cost);
  1288. PayRefineFee(cost);
  1289. }
  1290.  
  1291. return true;
  1292. }
  1293.  
  1294. enum enum_RefineScrolls
  1295. {
  1296. CHUKBOK_SCROLL = 0,
  1297. HYUNIRON_CHN = 1, // 중국에서만 사용
  1298. YONGSIN_SCROLL = 2,
  1299. MUSIN_SCROLL = 3,
  1300. YAGONG_SCROLL = 4,
  1301. MEMO_SCROLL = 5,
  1302. BDRAGON_SCROLL = 6,
  1303. };
  1304.  
  1305. bool CHARACTER::DoRefineWithScroll(LPITEM item)
  1306. {
  1307. if (!CanHandleItem(true))
  1308. {
  1309. ClearRefineMode();
  1310. return false;
  1311. }
  1312. ClearRefineMode();
  1313.  
  1314. //개량 시간제한 : upgrade_refine_scroll.quest 에서 개량후 5분이내에 일반 개량을
  1315. //진행할수 없음
  1316. if (quest::CQuestManager::instance().GetEventFlag("update_refine_time") != 0)
  1317. {
  1318. if (get_global_time() < quest::CQuestManager::instance().GetEventFlag("update_refine_time") + (60 * 5))
  1319. {
  1320. sys_log(0, "can't refine %d %s", GetPlayerID(), GetStringName().c_str());
  1321. return false;
  1322. }
  1323. }
  1324.  
  1325. const TRefineTable * prt = CRefineManager::instance().GetRefineRecipe(item->GetRefineSet());
  1326.  
  1327. if (!prt)
  1328. return false;
  1329.  
  1330. LPITEM pkItemScroll;
  1331.  
  1332. // 개량서 체크
  1333. if (m_iRefineAdditionalCell < 0)
  1334. return false;
  1335.  
  1336. pkItemScroll = GetInventoryItem(m_iRefineAdditionalCell);
  1337.  
  1338. if (!pkItemScroll)
  1339. return false;
  1340.  
  1341. if (!(pkItemScroll->GetType() == ITEM_USE && pkItemScroll->GetSubType() == USE_TUNING))
  1342. return false;
  1343.  
  1344. if (pkItemScroll->GetVnum() == item->GetVnum())
  1345. return false;
  1346.  
  1347. DWORD result_vnum = item->GetRefinedVnum();
  1348. DWORD result_fail_vnum = item->GetRefineFromVnum();
  1349.  
  1350. if (result_vnum == 0)
  1351. {
  1352. ChatInfoTrans(("더 이상 개량할 수 없습니다."));
  1353. return false;
  1354. }
  1355.  
  1356. // MUSIN_SCROLL
  1357. if (pkItemScroll->GetValue(0) == MUSIN_SCROLL)
  1358. {
  1359. if (item->GetRefineLevel() >= 4)
  1360. {
  1361. ChatInfoTrans(("이 개량서로 더 이상 개량할 수 없습니다."));
  1362. return false;
  1363. }
  1364. }
  1365. // END_OF_MUSIC_SCROLL
  1366.  
  1367. else if (pkItemScroll->GetValue(0) == MEMO_SCROLL)
  1368. {
  1369. if (item->GetRefineLevel() != pkItemScroll->GetValue(1))
  1370. {
  1371. ChatInfoTrans(("이 개량서로 개량할 수 없습니다."));
  1372. return false;
  1373. }
  1374. }
  1375. else if (pkItemScroll->GetValue(0) == BDRAGON_SCROLL)
  1376. {
  1377. if (item->GetType() != ITEM_METIN || item->GetRefineLevel() != 4)
  1378. {
  1379. ChatInfoTrans(("이 아이템으로 개량할 수 없습니다."));
  1380. return false;
  1381. }
  1382. }
  1383.  
  1384. TItemTable * pProto = ITEM_MANAGER::instance().GetTable(item->GetRefinedVnum());
  1385.  
  1386. if (!pProto)
  1387. {
  1388. sys_err("DoRefineWithScroll NOT GET ITEM PROTO %d", item->GetRefinedVnum());
  1389. ChatInfoTrans(("이 아이템은 개량할 수 없습니다."));
  1390. return false;
  1391. }
  1392.  
  1393. if (GetGold() < prt->cost)
  1394. {
  1395. ChatInfoTrans(("개량을 하기 위한 돈이 부족합니다."));
  1396. return false;
  1397. }
  1398.  
  1399. for (int i = 0; i < prt->material_count; ++i)
  1400. {
  1401. if (CountSpecifyItem(prt->materials[i].vnum) < prt->materials[i].count)
  1402. {
  1403. if (test_server)
  1404. {
  1405. ChatPacket(CHAT_TYPE_INFO, "Find %d, count %d, require %d", prt->materials[i].vnum, CountSpecifyItem(prt->materials[i].vnum), prt->materials[i].count);
  1406. }
  1407. ChatInfoTrans(("개량을 하기 위한 재료가 부족합니다."));
  1408. return false;
  1409. }
  1410. }
  1411.  
  1412. for (int i = 0; i < prt->material_count; ++i)
  1413. RemoveSpecifyItem(prt->materials[i].vnum, prt->materials[i].count);
  1414.  
  1415. int prob = number(1, 100);
  1416. int success_prob = prt->prob;
  1417. bool bDestroyWhenFail = false;
  1418.  
  1419. const char* szRefineType = "SCROLL";
  1420.  
  1421. if (pkItemScroll->GetValue(0) == HYUNIRON_CHN ||
  1422. pkItemScroll->GetValue(0) == YONGSIN_SCROLL ||
  1423. pkItemScroll->GetValue(0) == YAGONG_SCROLL) // 현철, 용신의 축복서, 야공의 비전서 처리
  1424. {
  1425. const char hyuniron_prob[9] = { 100, 75, 65, 55, 45, 40, 35, 25, 20 };
  1426. const char yagong_prob[9] = { 100, 100, 90, 80, 70, 60, 50, 30, 20 };
  1427.  
  1428. if (pkItemScroll->GetValue(0) == YONGSIN_SCROLL)
  1429. {
  1430. success_prob = hyuniron_prob[MINMAX(0, item->GetRefineLevel(), 8)];
  1431. }
  1432. else if (pkItemScroll->GetValue(0) == YAGONG_SCROLL)
  1433. {
  1434. success_prob = yagong_prob[MINMAX(0, item->GetRefineLevel(), 8)];
  1435. }
  1436. else if (pkItemScroll->GetValue(0) == HYUNIRON_CHN) {} // @fixme121
  1437. else
  1438. {
  1439. sys_err("REFINE : Unknown refine scroll item. Value0: %d", pkItemScroll->GetValue(0));
  1440. }
  1441.  
  1442. if (test_server)
  1443. {
  1444. ChatPacket(CHAT_TYPE_INFO, "[Only Test] Success_Prob %d, RefineLevel %d ", success_prob, item->GetRefineLevel());
  1445. }
  1446. if (pkItemScroll->GetValue(0) == HYUNIRON_CHN) // 현철은 아이템이 부서져야 한다.
  1447. bDestroyWhenFail = true;
  1448.  
  1449. // DETAIL_REFINE_LOG
  1450. if (pkItemScroll->GetValue(0) == HYUNIRON_CHN)
  1451. {
  1452. szRefineType = "HYUNIRON";
  1453. }
  1454. else if (pkItemScroll->GetValue(0) == YONGSIN_SCROLL)
  1455. {
  1456. szRefineType = "GOD_SCROLL";
  1457. }
  1458. else if (pkItemScroll->GetValue(0) == YAGONG_SCROLL)
  1459. {
  1460. szRefineType = "YAGONG_SCROLL";
  1461. }
  1462. // END_OF_DETAIL_REFINE_LOG
  1463. }
  1464.  
  1465. // DETAIL_REFINE_LOG
  1466. if (pkItemScroll->GetValue(0) == MUSIN_SCROLL) // 무신의 축복서는 100% 성공 (+4까지만)
  1467. {
  1468. success_prob = 100;
  1469.  
  1470. szRefineType = "MUSIN_SCROLL";
  1471. }
  1472. // END_OF_DETAIL_REFINE_LOG
  1473. else if (pkItemScroll->GetValue(0) == MEMO_SCROLL)
  1474. {
  1475. success_prob = 100;
  1476. szRefineType = "MEMO_SCROLL";
  1477. }
  1478. else if (pkItemScroll->GetValue(0) == BDRAGON_SCROLL)
  1479. {
  1480. success_prob = 80;
  1481. szRefineType = "BDRAGON_SCROLL";
  1482. }
  1483.  
  1484. pkItemScroll->SetCount(pkItemScroll->GetCount() - 0);
  1485.  
  1486. if (prob <= success_prob)
  1487. {
  1488. // 성공! 모든 아이템이 사라지고, 같은 속성의 다른 아이템 획득
  1489. LPITEM pkNewItem = ITEM_MANAGER::instance().CreateItem(result_vnum, 1, 0, false);
  1490.  
  1491. if (pkNewItem)
  1492. {
  1493. ITEM_MANAGER::CopyAllAttrTo(item, pkNewItem);
  1494. LogManager::instance().ItemLog(this, pkNewItem, "REFINE SUCCESS", pkNewItem->GetLocaleName(this));
  1495.  
  1496. BYTE bCell = item->GetCell();
  1497.  
  1498. NotifyRefineSuccess(this, item, szRefineType);
  1499. DBManager::instance().SendMoneyLog(MONEY_LOG_REFINE, item->GetVnum(), -prt->cost);
  1500. ITEM_MANAGER::instance().RemoveItem(item, "REMOVE (REFINE SUCCESS)");
  1501.  
  1502. pkNewItem->AddToCharacter(this, TItemPos(INVENTORY, bCell));
  1503. ITEM_MANAGER::instance().FlushDelayedSave(pkNewItem);
  1504. pkNewItem->AttrLog();
  1505. //PointChange(POINT_GOLD, -prt->cost);
  1506. PayRefineFee(prt->cost);
  1507. }
  1508. else
  1509. {
  1510. // 아이템 생성에 실패 -> 개량 실패로 간주
  1511. sys_err("cannot create item %u", result_vnum);
  1512. NotifyRefineFail(this, item, szRefineType);
  1513. }
  1514. }
  1515. else if (!bDestroyWhenFail && result_fail_vnum)
  1516. {
  1517. // 실패! 모든 아이템이 사라지고, 같은 속성의 낮은 등급의 아이템 획득
  1518. LPITEM pkNewItem = ITEM_MANAGER::instance().CreateItem(result_fail_vnum, 1, 0, false);
  1519.  
  1520. if (pkNewItem)
  1521. {
  1522. ITEM_MANAGER::CopyAllAttrTo(item, pkNewItem);
  1523. LogManager::instance().ItemLog(this, pkNewItem, "REFINE FAIL", pkNewItem->GetLocaleName(this));
  1524.  
  1525. BYTE bCell = item->GetCell();
  1526.  
  1527. DBManager::instance().SendMoneyLog(MONEY_LOG_REFINE, item->GetVnum(), -prt->cost);
  1528. NotifyRefineFail(this, item, szRefineType, -1);
  1529. ITEM_MANAGER::instance().RemoveItem(item, "REMOVE (REFINE FAIL)");
  1530.  
  1531. pkNewItem->AddToCharacter(this, TItemPos(INVENTORY, bCell));
  1532. ITEM_MANAGER::instance().FlushDelayedSave(pkNewItem);
  1533.  
  1534. pkNewItem->AttrLog();
  1535.  
  1536. //PointChange(POINT_GOLD, -prt->cost);
  1537. PayRefineFee(prt->cost);
  1538. }
  1539. else
  1540. {
  1541. // 아이템 생성에 실패 -> 개량 실패로 간주
  1542. sys_err("cannot create item %u", result_fail_vnum);
  1543. NotifyRefineFail(this, item, szRefineType);
  1544. }
  1545. }
  1546. else
  1547. {
  1548. NotifyRefineFail(this, item, szRefineType); // 개량시 아이템 사라지지 않음
  1549.  
  1550. PayRefineFee(prt->cost);
  1551. }
  1552.  
  1553. return true;
  1554. }
  1555.  
  1556. bool CHARACTER::RefineInformation(BYTE bCell, BYTE bType, int iAdditionalCell)
  1557. {
  1558. if (bCell > INVENTORY_MAX_NUM)
  1559. return false;
  1560.  
  1561. LPITEM item = GetInventoryItem(bCell);
  1562.  
  1563. if (!item)
  1564. return false;
  1565.  
  1566. // REFINE_COST
  1567. if (bType == REFINE_TYPE_MONEY_ONLY && !GetQuestFlag("deviltower_zone.can_refine"))
  1568. {
  1569. ChatInfoTrans(("사귀 타워 완료 보상은 한번까지 사용가능합니다."));
  1570. return false;
  1571. }
  1572. // END_OF_REFINE_COST
  1573.  
  1574. TPacketGCRefineInformation p;
  1575.  
  1576. p.header = HEADER_GC_REFINE_INFORMATION;
  1577. p.pos = bCell;
  1578. p.src_vnum = item->GetVnum();
  1579. p.result_vnum = item->GetRefinedVnum();
  1580. p.type = bType;
  1581.  
  1582. if (p.result_vnum == 0)
  1583. {
  1584. sys_err("RefineInformation p.result_vnum == 0");
  1585. ChatInfoTrans(("이 아이템은 개량할 수 없습니다."));
  1586. return false;
  1587. }
  1588.  
  1589. if (item->GetType() == ITEM_USE && item->GetSubType() == USE_TUNING)
  1590. {
  1591. if (bType == 0)
  1592. {
  1593. ChatInfoTrans(("이 아이템은 이 방식으로는 개량할 수 없습니다."));
  1594. return false;
  1595. }
  1596. else
  1597. {
  1598. LPITEM itemScroll = GetInventoryItem(iAdditionalCell);
  1599. if (!itemScroll || item->GetVnum() == itemScroll->GetVnum())
  1600. {
  1601. ChatInfoTrans(("같은 개량서를 합칠 수는 없습니다."));
  1602. ChatInfoTrans(("축복의 서와 현철을 합칠 수 있습니다."));
  1603. return false;
  1604. }
  1605. }
  1606. }
  1607.  
  1608. CRefineManager & rm = CRefineManager::instance();
  1609.  
  1610. const TRefineTable* prt = rm.GetRefineRecipe(item->GetRefineSet());
  1611.  
  1612. if (!prt)
  1613. {
  1614. sys_err("RefineInformation NOT GET REFINE SET %d", item->GetRefineSet());
  1615. ChatInfoTrans(("이 아이템은 개량할 수 없습니다."));
  1616. return false;
  1617. }
  1618.  
  1619. // REFINE_COST
  1620.  
  1621. //MAIN_QUEST_LV7
  1622. if (GetQuestFlag("main_quest_lv7.refine_chance") > 0)
  1623. {
  1624. // 일본은 제외
  1625. if (!item->CheckItemUseLevel(20) || item->GetType() != ITEM_WEAPON)
  1626. {
  1627. ChatInfoTrans(("무료 개량 기회는 20 이하의 무기만 가능합니다"));
  1628. return false;
  1629. }
  1630. p.cost = 0;
  1631. }
  1632. else
  1633. p.cost = ComputeRefineFee(prt->cost);
  1634.  
  1635. //END_MAIN_QUEST_LV7
  1636. p.prob = prt->prob;
  1637. if (bType == REFINE_TYPE_MONEY_ONLY)
  1638. {
  1639. p.material_count = 0;
  1640. memset(p.materials, 0, sizeof(p.materials));
  1641. }
  1642. else
  1643. {
  1644. p.material_count = prt->material_count;
  1645. thecore_memcpy(&p.materials, prt->materials, sizeof(prt->materials));
  1646. }
  1647. // END_OF_REFINE_COST
  1648.  
  1649. GetDesc()->Packet(&p, sizeof(TPacketGCRefineInformation));
  1650.  
  1651. SetRefineMode(iAdditionalCell);
  1652. return true;
  1653. }
  1654.  
  1655. bool CHARACTER::RefineItem(LPITEM pkItem, LPITEM pkTarget)
  1656. {
  1657. if (!CanHandleItem())
  1658. return false;
  1659.  
  1660. if (pkItem->GetSubType() == USE_TUNING)
  1661. {
  1662. // XXX 성능, 소켓 개량서는 사라졌습니다...
  1663. // XXX 성능개량서는 축복의 서가 되었다!
  1664. // MUSIN_SCROLL
  1665. if (pkItem->GetValue(0) == MUSIN_SCROLL)
  1666. RefineInformation(pkTarget->GetCell(), REFINE_TYPE_MUSIN, pkItem->GetCell());
  1667. // END_OF_MUSIN_SCROLL
  1668. else if (pkItem->GetValue(0) == HYUNIRON_CHN)
  1669. RefineInformation(pkTarget->GetCell(), REFINE_TYPE_HYUNIRON, pkItem->GetCell());
  1670. else if (pkItem->GetValue(0) == BDRAGON_SCROLL)
  1671. {
  1672. if (pkTarget->GetRefineSet() != 702) return false;
  1673. RefineInformation(pkTarget->GetCell(), REFINE_TYPE_BDRAGON, pkItem->GetCell());
  1674. }
  1675. else
  1676. {
  1677. if (pkTarget->GetRefineSet() == 501) return false;
  1678. RefineInformation(pkTarget->GetCell(), REFINE_TYPE_SCROLL, pkItem->GetCell());
  1679. }
  1680. }
  1681. else if (pkItem->GetSubType() == USE_DETACHMENT && IS_SET(pkTarget->GetFlag(), ITEM_FLAG_REFINEABLE))
  1682. {
  1683. LogManager::instance().ItemLog(this, pkTarget, "USE_DETACHMENT", pkTarget->GetLocaleName(this));
  1684.  
  1685. bool bHasMetinStone = false;
  1686.  
  1687. for (int i = 0; i < ITEM_SOCKET_MAX_NUM; i++)
  1688. {
  1689. long socket = pkTarget->GetSocket(i);
  1690. if (socket > 2 && socket != ITEM_BROKEN_METIN_VNUM)
  1691. {
  1692. bHasMetinStone = true;
  1693. break;
  1694. }
  1695. }
  1696.  
  1697. if (bHasMetinStone)
  1698. {
  1699. for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
  1700. {
  1701. long socket = pkTarget->GetSocket(i);
  1702. if (socket > 2 && socket != ITEM_BROKEN_METIN_VNUM)
  1703. {
  1704. AutoGiveItem(socket);
  1705. //TItemTable* pTable = ITEM_MANAGER::instance().GetTable(pkTarget->GetSocket(i));
  1706. //pkTarget->SetSocket(i, pTable->alValues[2]);
  1707. // 깨진돌로 대체해준다
  1708. pkTarget->SetSocket(i, ITEM_BROKEN_METIN_VNUM);
  1709. }
  1710. }
  1711. pkItem->SetCount(pkItem->GetCount() - 0);
  1712. return true;
  1713. }
  1714. else
  1715. {
  1716. ChatInfoTrans(("빼낼 수 있는 메틴석이 없습니다."));
  1717. return false;
  1718. }
  1719. }
  1720.  
  1721. return false;
  1722. }
  1723.  
  1724. EVENTFUNC(kill_campfire_event)
  1725. {
  1726. char_event_info* info = dynamic_cast<char_event_info*>( event->info );
  1727.  
  1728. if ( info == NULL )
  1729. {
  1730. sys_err( "kill_campfire_event> <Factor> Null pointer" );
  1731. return 0;
  1732. }
  1733.  
  1734. LPCHARACTER ch = info->ch;
  1735.  
  1736. if (ch == NULL) { // <Factor>
  1737. return 0;
  1738. }
  1739. ch->m_pkMiningEvent = NULL;
  1740. M2_DESTROY_CHARACTER(ch);
  1741. return 0;
  1742. }
  1743.  
  1744. bool CHARACTER::GiveRecallItem(LPITEM item)
  1745. {
  1746. int idx = GetMapIndex();
  1747. int iEmpireByMapIndex = -1;
  1748.  
  1749. if (idx < 20)
  1750. iEmpireByMapIndex = 1;
  1751. else if (idx < 40)
  1752. iEmpireByMapIndex = 2;
  1753. else if (idx < 60)
  1754. iEmpireByMapIndex = 3;
  1755. else if (idx < 10000)
  1756. iEmpireByMapIndex = 0;
  1757.  
  1758. switch (idx)
  1759. {
  1760. case 66:
  1761. case 216:
  1762. iEmpireByMapIndex = -1;
  1763. break;
  1764. }
  1765.  
  1766. if (iEmpireByMapIndex && GetEmpire() != iEmpireByMapIndex)
  1767. {
  1768. ChatInfoTrans(("기억해 둘 수 없는 위치 입니다."));
  1769. return false;
  1770. }
  1771.  
  1772. int pos;
  1773.  
  1774. if (item->GetCount() == 1) // 아이템이 하나라면 그냥 셋팅.
  1775. {
  1776. item->SetSocket(0, GetX());
  1777. item->SetSocket(1, GetY());
  1778. }
  1779. else if ((pos = GetEmptyInventory(item->GetSize())) != -1) // 그렇지 않다면 다른 인벤토리 슬롯을 찾는다.
  1780. {
  1781. LPITEM item2 = ITEM_MANAGER::instance().CreateItem(item->GetVnum(), 1);
  1782.  
  1783. if (NULL != item2)
  1784. {
  1785. item2->SetSocket(0, GetX());
  1786. item2->SetSocket(1, GetY());
  1787. item2->AddToCharacter(this, TItemPos(INVENTORY, pos));
  1788.  
  1789. item->SetCount(item->GetCount() - 0);
  1790. }
  1791. }
  1792. else
  1793. {
  1794. ChatInfoTrans(("소지품에 빈 공간이 없습니다."));
  1795. return false;
  1796. }
  1797.  
  1798. return true;
  1799. }
  1800.  
  1801. void CHARACTER::ProcessRecallItem(LPITEM item)
  1802. {
  1803. int idx;
  1804.  
  1805. if ((idx = SECTREE_MANAGER::instance().GetMapIndex(item->GetSocket(0), item->GetSocket(1))) == 0)
  1806. return;
  1807.  
  1808. int iEmpireByMapIndex = -1;
  1809.  
  1810. if (idx < 20)
  1811. iEmpireByMapIndex = 1;
  1812. else if (idx < 40)
  1813. iEmpireByMapIndex = 2;
  1814. else if (idx < 60)
  1815. iEmpireByMapIndex = 3;
  1816. else if (idx < 10000)
  1817. iEmpireByMapIndex = 0;
  1818.  
  1819. switch (idx)
  1820. {
  1821. case 66:
  1822. case 216:
  1823. iEmpireByMapIndex = -1;
  1824. break;
  1825. // 악룡군도 일때
  1826. case 301:
  1827. case 302:
  1828. case 303:
  1829. case 304:
  1830. if( GetLevel() < 90 )
  1831. {
  1832. ChatInfoTrans(("아이템의 레벨 제한보다 레벨이 낮습니다."));
  1833. return;
  1834. }
  1835. else
  1836. break;
  1837. }
  1838.  
  1839. if (iEmpireByMapIndex && GetEmpire() != iEmpireByMapIndex)
  1840. {
  1841. ChatInfoTrans(("기억된 위치가 타제국에 속해 있어서 귀환할 수 없습니다."));
  1842. item->SetSocket(0, 0);
  1843. item->SetSocket(1, 0);
  1844. }
  1845. else
  1846. {
  1847. sys_log(1, "Recall: %s %d %d -> %d %d", GetStringName().c_str(), GetX(), GetY(), item->GetSocket(0), item->GetSocket(1));
  1848. WarpSet(item->GetSocket(0), item->GetSocket(1));
  1849. item->SetCount(item->GetCount() - 0);
  1850. }
  1851. }
  1852.  
  1853. void CHARACTER::__OpenPrivateShop()
  1854. {
  1855. unsigned bodyPart = GetPart(PART_MAIN);
  1856. switch (bodyPart)
  1857. {
  1858. case 0:
  1859. case 1:
  1860. case 2:
  1861. ChatPacket(CHAT_TYPE_COMMAND, "OpenPrivateShop");
  1862. break;
  1863. default:
  1864. ChatInfoTrans(("갑옷을 벗어야 개인 상점을 열 수 있습니다."));
  1865. break;
  1866. }
  1867. }
  1868.  
  1869. // MYSHOP_PRICE_LIST
  1870. void CHARACTER::SendMyShopPriceListCmd(DWORD dwItemVnum, DWORD dwItemPrice)
  1871. {
  1872. char szLine[256];
  1873. snprintf(szLine, sizeof(szLine), "MyShopPriceList %u %u", dwItemVnum, dwItemPrice);
  1874. ChatPacket(CHAT_TYPE_COMMAND, szLine);
  1875. sys_log(0, szLine);
  1876. }
  1877.  
  1878. //
  1879. // DB 캐시로 부터 받은 리스트를 User 에게 전송하고 상점을 열라는 커맨드를 보낸다.
  1880. //
  1881. void CHARACTER::UseSilkBotaryReal(const TPacketMyshopPricelistHeader* p)
  1882. {
  1883. const TItemPriceInfo* pInfo = (const TItemPriceInfo*)(p + 1);
  1884.  
  1885. if (!p->byCount)
  1886. // 가격 리스트가 없다. dummy 데이터를 넣은 커맨드를 보내준다.
  1887. SendMyShopPriceListCmd(1, 0);
  1888. else {
  1889. for (int idx = 0; idx < p->byCount; idx++)
  1890. SendMyShopPriceListCmd(pInfo[ idx ].dwVnum, pInfo[ idx ].dwPrice);
  1891. }
  1892.  
  1893. __OpenPrivateShop();
  1894. }
  1895.  
  1896. //
  1897. // 이번 접속 후 처음 상점을 Open 하는 경우 리스트를 Load 하기 위해 DB 캐시에 가격정보 리스트 요청 패킷을 보낸다.
  1898. // 이후부터는 바로 상점을 열라는 응답을 보낸다.
  1899. //
  1900. void CHARACTER::UseSilkBotary(void)
  1901. {
  1902. if (m_bNoOpenedShop) {
  1903. DWORD dwPlayerID = GetPlayerID();
  1904. db_clientdesc->DBPacket(HEADER_GD_MYSHOP_PRICELIST_REQ, GetDesc()->GetHandle(), &dwPlayerID, sizeof(DWORD));
  1905. m_bNoOpenedShop = false;
  1906. } else {
  1907. __OpenPrivateShop();
  1908. }
  1909. }
  1910. // END_OF_MYSHOP_PRICE_LIST
  1911.  
  1912.  
  1913. int CalculateConsume(LPCHARACTER ch)
  1914. {
  1915. static const int WARP_NEED_LIFE_PERCENT = 30;
  1916. static const int WARP_MIN_LIFE_PERCENT = 10;
  1917. // CONSUME_LIFE_WHEN_USE_WARP_ITEM
  1918. int consumeLife = 0;
  1919. {
  1920. // CheckNeedLifeForWarp
  1921. const int curLife = ch->GetHP();
  1922. const int needPercent = WARP_NEED_LIFE_PERCENT;
  1923. const int needLife = ch->GetMaxHP() * needPercent / 100;
  1924. if (curLife < needLife)
  1925. {
  1926. ch->ChatInfoTrans(("남은 생명력 양이 모자라 사용할 수 없습니다."));
  1927. return -1;
  1928. }
  1929.  
  1930. consumeLife = needLife;
  1931.  
  1932.  
  1933. // CheckMinLifeForWarp: 독에 의해서 죽으면 안되므로 생명력 최소량는 남겨준다
  1934. const int minPercent = WARP_MIN_LIFE_PERCENT;
  1935. const int minLife = ch->GetMaxHP() * minPercent / 100;
  1936. if (curLife - needLife < minLife)
  1937. consumeLife = curLife - minLife;
  1938.  
  1939. if (consumeLife < 0)
  1940. consumeLife = 0;
  1941. }
  1942. // END_OF_CONSUME_LIFE_WHEN_USE_WARP_ITEM
  1943. return consumeLife;
  1944. }
  1945.  
  1946. int CalculateConsumeSP(LPCHARACTER lpChar)
  1947. {
  1948. static const int NEED_WARP_SP_PERCENT = 30;
  1949.  
  1950. const int curSP = lpChar->GetSP();
  1951. const int needSP = lpChar->GetMaxSP() * NEED_WARP_SP_PERCENT / 100;
  1952.  
  1953. if (curSP < needSP)
  1954. {
  1955. lpChar->ChatInfoTrans(("남은 정신력 양이 모자라 사용할 수 없습니다."));
  1956. return -1;
  1957. }
  1958.  
  1959. return needSP;
  1960. }
  1961.  
  1962. // #define ENABLE_FIREWORK_STUN
  1963. #define ENABLE_ADDSTONE_FAILURE
  1964. bool CHARACTER::UseItemEx(LPITEM item, TItemPos DestCell)
  1965. {
  1966. int iLimitRealtimeStartFirstUseFlagIndex = -1;
  1967. //int iLimitTimerBasedOnWearFlagIndex = -1;
  1968.  
  1969. WORD wDestCell = DestCell.cell;
  1970. BYTE bDestInven = DestCell.window_type;
  1971. for (int i = 0; i < ITEM_LIMIT_MAX_NUM; ++i)
  1972. {
  1973. long limitValue = item->GetProto()->aLimits[i].lValue;
  1974.  
  1975. switch (item->GetProto()->aLimits[i].bType)
  1976. {
  1977. case LIMIT_LEVEL:
  1978. if (GetLevel() < limitValue)
  1979. {
  1980. ChatInfoTrans(("아이템의 레벨 제한보다 레벨이 낮습니다."));
  1981. return false;
  1982. }
  1983. break;
  1984.  
  1985. case LIMIT_CHAMPION:
  1986. if (GetConquerorLevel() < limitValue)
  1987. {
  1988. ChatInfoTrans(("아이템의 레벨 제한보다 레벨이 낮습니다."));
  1989. return false;
  1990. }
  1991. break;
  1992.  
  1993. case LIMIT_REAL_TIME_START_FIRST_USE:
  1994. iLimitRealtimeStartFirstUseFlagIndex = i;
  1995. break;
  1996.  
  1997. case LIMIT_TIMER_BASED_ON_WEAR:
  1998. //iLimitTimerBasedOnWearFlagIndex = i;
  1999. break;
  2000. }
  2001. }
  2002. if (test_server)
  2003. {
  2004. sys_log(0, "USE_ITEM %s, Inven %d, Cell %d, ItemType %d, SubType %d", item->GetLocaleName(this), bDestInven, wDestCell, item->GetType(), item->GetSubType());
  2005. }
  2006.  
  2007. if ( CArenaManager::instance().IsLimitedItem( GetMapIndex(), item->GetVnum() ) == true )
  2008. {
  2009. ChatInfoTrans(("대련 중에는 이용할 수 없는 물품입니다."));
  2010. return false;
  2011. }
  2012.  
  2013. // @fixme402 (IsLoadedAffect to block affect hacking)
  2014. // if (!IsLoadedAffect())
  2015. // {
  2016. // ChatPacket(CHAT_TYPE_INFO, "Affects are not loaded yet!");
  2017. // return false;
  2018. // }
  2019.  
  2020. // @fixme141 BEGIN
  2021. if (TItemPos(item->GetWindow(), item->GetCell()).IsBeltInventoryPosition())
  2022. {
  2023. LPITEM beltItem = GetWear(WEAR_BELT);
  2024.  
  2025. if (NULL == beltItem)
  2026. {
  2027. ChatPacket(CHAT_TYPE_INFO, "<Belt> You can't use this item if you have no equipped belt.");
  2028. return false;
  2029. }
  2030.  
  2031. if (false == CBeltInventoryHelper::IsAvailableCell(item->GetCell() - BELT_INVENTORY_SLOT_START, beltItem->GetValue(0)))
  2032. {
  2033. ChatPacket(CHAT_TYPE_INFO, "<Belt> You can't use this item if you don't upgrade your belt.");
  2034. return false;
  2035. }
  2036. }
  2037. // @fixme141 END
  2038.  
  2039. // 아이템 최초 사용 이후부터는 사용하지 않아도 시간이 차감되는 방식 처리.
  2040. if (-1 != iLimitRealtimeStartFirstUseFlagIndex)
  2041. {
  2042. // 한 번이라도 사용한 아이템인지 여부는 Socket1을 보고 판단한다. (Socket1에 사용횟수 기록)
  2043. if (0 == item->GetSocket(1))
  2044. {
  2045. // 사용가능시간은 Default 값으로 Limit Value 값을 사용하되, Socket0에 값이 있으면 그 값을 사용하도록 한다. (단위는 초)
  2046. long duration = (0 != item->GetSocket(0)) ? item->GetSocket(0) : item->GetProto()->aLimits[iLimitRealtimeStartFirstUseFlagIndex].lValue;
  2047.  
  2048. if (0 == duration)
  2049. duration = 60 * 60 * 24 * 7;
  2050.  
  2051. item->SetSocket(0, time(0) + duration);
  2052. item->StartRealTimeExpireEvent();
  2053. }
  2054.  
  2055. if (false == item->IsEquipped())
  2056. item->SetSocket(1, item->GetSocket(1) + 1);
  2057. }
  2058.  
  2059. #ifdef __BATTLE_PASS__
  2060. if (!v_counts.empty())
  2061. {
  2062. for (int i=0; i<missions_bp.size(); ++i)
  2063. {
  2064. if (missions_bp[i].type == 1 && item->GetVnum() == missions_bp[i].vnum)
  2065. {
  2066. DoMission(i, 1);
  2067. }
  2068. }
  2069. }
  2070. #endif
  2071.  
  2072. #ifdef ENABLE_AUTONAME_SYSTEM
  2073. if (item->GetVnum() == AUTONAME_SCROLL_VNUM)
  2074. ChatPacket(CHAT_TYPE_COMMAND, "OpenAutoNameSystem");
  2075. #endif
  2076.  
  2077. #ifdef ENABLE_COINS_SYSTEM
  2078. switch (item->GetVnum())
  2079. {
  2080. case 30510:
  2081. case 30513:
  2082. case 30516:
  2083. case 30155:
  2084. case 30156:
  2085. case 30158:
  2086. if (!CanHandleItem())
  2087. return false;
  2088.  
  2089. if (IsOpenSafebox() || GetExchange() || GetMyShop() || IsCubeOpen())
  2090. return false;
  2091.  
  2092. SetCoins(true, 0, item->GetVnum());
  2093. item->SetCount(item->GetCount() - 1);
  2094.  
  2095. return 1;
  2096. break;
  2097. default:
  2098. break;
  2099. }
  2100.  
  2101. switch (item->GetVnum())
  2102. {
  2103. case 30200:
  2104. case 30201:
  2105. case 30202:
  2106. case 30203:
  2107. case 30204:
  2108. case 30205:
  2109. if (!CanHandleItem())
  2110. return false;
  2111.  
  2112. if (IsOpenSafebox() || GetExchange() || GetMyShop() || IsCubeOpen())
  2113. return false;
  2114.  
  2115. SetJD(true, 0, item->GetVnum());
  2116. item->SetCount(item->GetCount() - 1);
  2117.  
  2118. return 1;
  2119. break;
  2120. default:
  2121. break;
  2122. }
  2123. #endif
  2124.  
  2125. switch (item->GetType())
  2126. {
  2127. case ITEM_HAIR:
  2128. return ItemProcess_Hair(item, wDestCell);
  2129.  
  2130. case ITEM_POLYMORPH:
  2131. return ItemProcess_Polymorph(item);
  2132.  
  2133. case ITEM_QUEST:
  2134. if (GetArena() != NULL || IsObserverMode() == true)
  2135. {
  2136. if (item->GetVnum() == 50051 || item->GetVnum() == 50052 || item->GetVnum() == 50053)
  2137. {
  2138. ChatInfoTrans(("대련 중에는 이용할 수 없는 물품입니다."));
  2139. return false;
  2140. }
  2141. }
  2142.  
  2143. if (!IS_SET(item->GetFlag(), ITEM_FLAG_QUEST_USE | ITEM_FLAG_QUEST_USE_MULTIPLE))
  2144. {
  2145. if (item->GetSIGVnum() == 0)
  2146. {
  2147. quest::CQuestManager::instance().UseItem(GetPlayerID(), item, false);
  2148. }
  2149. else
  2150. {
  2151. quest::CQuestManager::instance().SIGUse(GetPlayerID(), item->GetSIGVnum(), item, false);
  2152. }
  2153. }
  2154. break;
  2155.  
  2156. case ITEM_CAMPFIRE:
  2157. {
  2158. float fx, fy;
  2159. GetDeltaByDegree(GetRotation(), 100.0f, &fx, &fy);
  2160.  
  2161. LPSECTREE tree = SECTREE_MANAGER::instance().Get(GetMapIndex(), (long)(GetX()+fx), (long)(GetY()+fy));
  2162.  
  2163. if (!tree)
  2164. {
  2165. ChatInfoTrans(("모닥불을 피울 수 없는 지점입니다."));
  2166. return false;
  2167. }
  2168.  
  2169. if (tree->IsAttr((long)(GetX()+fx), (long)(GetY()+fy), ATTR_WATER))
  2170. {
  2171. ChatInfoTrans(("물 속에 모닥불을 피울 수 없습니다."));
  2172. return false;
  2173. }
  2174.  
  2175. LPCHARACTER campfire = CHARACTER_MANAGER::instance().SpawnMob(fishing::CAMPFIRE_MOB, GetMapIndex(), (long)(GetX()+fx), (long)(GetY()+fy), 0, false, number(0, 359));
  2176.  
  2177. char_event_info* info = AllocEventInfo<char_event_info>();
  2178.  
  2179. info->ch = campfire;
  2180.  
  2181. campfire->m_pkMiningEvent = event_create(kill_campfire_event, info, PASSES_PER_SEC(40));
  2182.  
  2183. item->SetCount(item->GetCount() - 0);
  2184. }
  2185. break;
  2186.  
  2187. case ITEM_UNIQUE:
  2188. {
  2189. switch (item->GetSubType())
  2190. {
  2191. case USE_ABILITY_UP:
  2192. {
  2193. switch (item->GetValue(0))
  2194. {
  2195. case APPLY_MOV_SPEED:
  2196. AddAffect(AFFECT_UNIQUE_ABILITY, POINT_MOV_SPEED, item->GetValue(2), AFF_MOV_SPEED_POTION, item->GetValue(1), 0, true, true);
  2197. break;
  2198.  
  2199. case APPLY_ATT_SPEED:
  2200. AddAffect(AFFECT_UNIQUE_ABILITY, POINT_ATT_SPEED, item->GetValue(2), AFF_ATT_SPEED_POTION, item->GetValue(1), 0, true, true);
  2201. break;
  2202.  
  2203. case APPLY_STR:
  2204. AddAffect(AFFECT_UNIQUE_ABILITY, POINT_ST, item->GetValue(2), 0, item->GetValue(1), 0, true, true);
  2205. break;
  2206.  
  2207. case APPLY_DEX:
  2208. AddAffect(AFFECT_UNIQUE_ABILITY, POINT_DX, item->GetValue(2), 0, item->GetValue(1), 0, true, true);
  2209. break;
  2210.  
  2211. case APPLY_CON:
  2212. AddAffect(AFFECT_UNIQUE_ABILITY, POINT_HT, item->GetValue(2), 0, item->GetValue(1), 0, true, true);
  2213. break;
  2214.  
  2215. case APPLY_INT:
  2216. AddAffect(AFFECT_UNIQUE_ABILITY, POINT_IQ, item->GetValue(2), 0, item->GetValue(1), 0, true, true);
  2217. break;
  2218.  
  2219. case APPLY_CAST_SPEED:
  2220. AddAffect(AFFECT_UNIQUE_ABILITY, POINT_CASTING_SPEED, item->GetValue(2), 0, item->GetValue(1), 0, true, true);
  2221. break;
  2222.  
  2223. case APPLY_RESIST_MAGIC:
  2224. AddAffect(AFFECT_UNIQUE_ABILITY, POINT_RESIST_MAGIC, item->GetValue(2), 0, item->GetValue(1), 0, true, true);
  2225. break;
  2226.  
  2227. case APPLY_ATT_GRADE_BONUS:
  2228. AddAffect(AFFECT_UNIQUE_ABILITY, POINT_ATT_GRADE_BONUS,
  2229. item->GetValue(2), 0, item->GetValue(1), 0, true, true);
  2230. break;
  2231.  
  2232. case APPLY_DEF_GRADE_BONUS:
  2233. AddAffect(AFFECT_UNIQUE_ABILITY, POINT_DEF_GRADE_BONUS,
  2234. item->GetValue(2), 0, item->GetValue(1), 0, true, true);
  2235. break;
  2236. }
  2237. }
  2238.  
  2239. if (GetDungeon())
  2240. GetDungeon()->UsePotion(this);
  2241.  
  2242. if (GetWarMap())
  2243. GetWarMap()->UsePotion(this, item);
  2244.  
  2245. item->SetCount(item->GetCount() - 0);
  2246. break;
  2247.  
  2248. default:
  2249. {
  2250. if (item->GetSubType() == USE_SPECIAL)
  2251. {
  2252. sys_log(0, "ITEM_UNIQUE: USE_SPECIAL %u", item->GetVnum());
  2253.  
  2254. switch (item->GetVnum())
  2255. {
  2256. case 71049: // 비단보따리
  2257. if (g_bEnableBootaryCheck)
  2258. {
  2259. if (IS_BOTARYABLE_ZONE(GetMapIndex()) == true)
  2260. {
  2261. UseSilkBotary();
  2262. }
  2263. else
  2264. {
  2265. ChatInfoTrans(("개인 상점을 열 수 없는 지역입니다"));
  2266. }
  2267. }
  2268. else
  2269. {
  2270. UseSilkBotary();
  2271. }
  2272. break;
  2273. }
  2274. }
  2275. else
  2276. {
  2277. if (!item->IsEquipped())
  2278. EquipItem(item);
  2279. else
  2280. UnequipItem(item);
  2281. }
  2282. }
  2283. break;
  2284. }
  2285. }
  2286. break;
  2287.  
  2288. case ITEM_COSTUME:
  2289. #ifdef ITEM_TITLE_EQUIP
  2290. case ITEM_NORMAL_TITLE:
  2291. #endif
  2292. if (GetMapIndex() == 112)
  2293. return false;
  2294.  
  2295. if (!item->IsEquipped())
  2296. EquipItem(item);
  2297. else
  2298. UnequipItem(item);
  2299. break;
  2300. case ITEM_WEAPON:
  2301. case ITEM_ARMOR:
  2302. case ITEM_ROD:
  2303. case ITEM_RING: // 신규 반지 아이템
  2304. case ITEM_FACE:
  2305. case ITEM_BELT: // 신규 벨트 아이템
  2306. case ITEM_CROWN:
  2307. #ifdef ENABLE_SLOT_PET_SYSTEM
  2308. case ITEM_PET:
  2309. #endif
  2310. case ITEM_PICK:
  2311. // END_OF_MINING
  2312. if (!item->IsEquipped())
  2313. EquipItem(item);
  2314. else
  2315. UnequipItem(item);
  2316. break;
  2317. // 착용하지 않은 용혼석은 사용할 수 없다.
  2318. // 정상적인 클라라면, 용혼석에 관하여 item use 패킷을 보낼 수 없다.
  2319. // 용혼석 착용은 item move 패킷으로 한다.
  2320. // 착용한 용혼석은 추출한다.
  2321. case ITEM_DS:
  2322. {
  2323. if (!item->IsEquipped())
  2324. return false;
  2325. return DSManager::instance().PullOut(this, NPOS, item);
  2326. break;
  2327. }
  2328. case ITEM_SPECIAL_DS:
  2329. if (!item->IsEquipped())
  2330. EquipItem(item);
  2331. else
  2332. UnequipItem(item);
  2333. break;
  2334.  
  2335. case ITEM_FISH:
  2336. {
  2337. if (CArenaManager::instance().IsArenaMap(GetMapIndex()) == true)
  2338. {
  2339. ChatInfoTrans(("대련 중에는 이용할 수 없는 물품입니다."));
  2340. return false;
  2341. }
  2342.  
  2343. if (item->GetSubType() == FISH_ALIVE)
  2344. fishing::UseFish(this, item);
  2345. }
  2346. break;
  2347.  
  2348. case ITEM_TREASURE_BOX:
  2349. {
  2350. return false;
  2351. //ChatInfoTrans("열쇠로 잠겨 있어서 열리지 않는것 같다. 열쇠를 구해보자."));
  2352. }
  2353. break;
  2354.  
  2355. case ITEM_TREASURE_KEY:
  2356. {
  2357. LPITEM item2;
  2358.  
  2359. if (!GetItem(DestCell) || !(item2 = GetItem(DestCell)))
  2360. return false;
  2361.  
  2362. if (item2->IsExchanging() || item2->IsEquipped()) // @fixme114
  2363. return false;
  2364.  
  2365. if (item2->GetType() != ITEM_TREASURE_BOX)
  2366. {
  2367. ChatInfoTrans(("열쇠로 여는 물건이 아닌것 같다."));
  2368. return false;
  2369. }
  2370.  
  2371. if (item->GetValue(0) == item2->GetValue(0))
  2372. {
  2373. //ChatInfoTrans("열쇠는 맞으나 아이템 주는 부분 구현이 안되었습니다."));
  2374. DWORD dwBoxVnum = item2->GetVnum();
  2375. std::vector <DWORD> dwVnums;
  2376. std::vector <DWORD> dwCounts;
  2377. std::vector <LPITEM> item_gets(0);
  2378. int count = 0;
  2379.  
  2380. if (GiveItemFromSpecialItemGroup(dwBoxVnum, dwVnums, dwCounts, item_gets, count))
  2381. {
  2382. ITEM_MANAGER::instance().RemoveItem(item);
  2383. ITEM_MANAGER::instance().RemoveItem(item2);
  2384.  
  2385. for (int i = 0; i < count; i++){
  2386. switch (dwVnums[i])
  2387. {
  2388. case CSpecialItemGroup::GOLD:
  2389. ChatInfoTrans(("돈 %d 냥을 획득했습니다."), dwCounts[i]);
  2390. break;
  2391. case CSpecialItemGroup::EXP:
  2392. ChatInfoTrans(("상자에서 부터 신비한 빛이 나옵니다."));
  2393. ChatInfoTrans(("%d의 경험치를 획득했습니다."), dwCounts[i]);
  2394. break;
  2395. case CSpecialItemGroup::MOB:
  2396. ChatInfoTrans(("상자에서 몬스터가 나타났습니다!"));
  2397. break;
  2398. case CSpecialItemGroup::SLOW:
  2399. ChatInfoTrans(("상자에서 나온 빨간 연기를 들이마시자 움직이는 속도가 느려졌습니다!"));
  2400. break;
  2401. case CSpecialItemGroup::DRAIN_HP:
  2402. ChatInfoTrans(("상자가 갑자기 폭발하였습니다! 생명력이 감소했습니다."));
  2403. break;
  2404. case CSpecialItemGroup::POISON:
  2405. ChatInfoTrans(("상자에서 나온 녹색 연기를 들이마시자 독이 온몸으로 퍼집니다!"));
  2406. break;
  2407. #ifdef ENABLE_WOLFMAN_CHARACTER
  2408. case CSpecialItemGroup::BLEEDING:
  2409. ChatInfoTrans(("상자에서 나온 녹색 연기를 들이마시자 독이 온몸으로 퍼집니다!"));
  2410. break;
  2411. #endif
  2412. case CSpecialItemGroup::MOB_GROUP:
  2413. ChatInfoTrans(("상자에서 몬스터가 나타났습니다!"));
  2414. break;
  2415. default:
  2416. if (item_gets[i])
  2417. {
  2418. if (dwCounts[i] > 1)
  2419. ChatInfoTrans(("상자에서 %s 가 %d 개 나왔습니다."), item_gets[i]->GetLocaleName(this), dwCounts[i]);
  2420. else
  2421. ChatInfoTrans(("상자에서 %s 가 나왔습니다."), item_gets[i]->GetLocaleName(this));
  2422.  
  2423. }
  2424. }
  2425. }
  2426. }
  2427. else
  2428. {
  2429. ChatInfoTrans(("열쇠가 맞지 않는 것 같다."));
  2430. return false;
  2431. }
  2432. }
  2433. else
  2434. {
  2435. ChatInfoTrans(("열쇠가 맞지 않는 것 같다."));
  2436. return false;
  2437. }
  2438. }
  2439. break;
  2440.  
  2441. case ITEM_GIFTBOX:
  2442. {
  2443. #ifdef ENABLE_NEWSTUFF
  2444. if (0 != g_BoxUseTimeLimitValue)
  2445. {
  2446. if (get_dword_time() < m_dwLastBoxUseTime+g_BoxUseTimeLimitValue)
  2447. {
  2448. ChatInfoTrans(("아직 골드를 버릴 수 없습니다."));
  2449. return false;
  2450. }
  2451. }
  2452.  
  2453. m_dwLastBoxUseTime = get_dword_time();
  2454. #endif
  2455. DWORD dwBoxVnum = item->GetVnum();
  2456. std::vector <DWORD> dwVnums;
  2457. std::vector <DWORD> dwCounts;
  2458. std::vector <LPITEM> item_gets(0);
  2459. int count = 0;
  2460.  
  2461. if( dwBoxVnum > 51500 && dwBoxVnum < 52000 ) // 용혼원석들
  2462. {
  2463. if( !(this->DragonSoul_IsQualified()) )
  2464. {
  2465. ChatPacket(CHAT_TYPE_INFO,LC_TEXT("먼저 용혼석 퀘스트를 완료하셔야 합니다."));
  2466. return false;
  2467. }
  2468. }
  2469.  
  2470. if (GiveItemFromSpecialItemGroup(dwBoxVnum, dwVnums, dwCounts, item_gets, count))
  2471. {
  2472. item->SetCount(item->GetCount()-1);
  2473.  
  2474. for (int i = 0; i < count; i++){
  2475. switch (dwVnums[i])
  2476. {
  2477. case CSpecialItemGroup::GOLD:
  2478. ChatInfoTrans(("돈 %d 냥을 획득했습니다."), dwCounts[i]);
  2479. break;
  2480. case CSpecialItemGroup::EXP:
  2481. ChatInfoTrans(("상자에서 부터 신비한 빛이 나옵니다."));
  2482. ChatInfoTrans(("%d의 경험치를 획득했습니다."), dwCounts[i]);
  2483. break;
  2484. case CSpecialItemGroup::MOB:
  2485. ChatInfoTrans(("상자에서 몬스터가 나타났습니다!"));
  2486. break;
  2487. case CSpecialItemGroup::SLOW:
  2488. ChatInfoTrans(("상자에서 나온 빨간 연기를 들이마시자 움직이는 속도가 느려졌습니다!"));
  2489. break;
  2490. case CSpecialItemGroup::DRAIN_HP:
  2491. ChatInfoTrans(("상자가 갑자기 폭발하였습니다! 생명력이 감소했습니다."));
  2492. break;
  2493. case CSpecialItemGroup::POISON:
  2494. ChatInfoTrans(("상자에서 나온 녹색 연기를 들이마시자 독이 온몸으로 퍼집니다!"));
  2495. break;
  2496. #ifdef ENABLE_WOLFMAN_CHARACTER
  2497. case CSpecialItemGroup::BLEEDING:
  2498. ChatInfoTrans(("상자에서 나온 녹색 연기를 들이마시자 독이 온몸으로 퍼집니다!"));
  2499. break;
  2500. #endif
  2501. case CSpecialItemGroup::MOB_GROUP:
  2502. ChatInfoTrans(("상자에서 몬스터가 나타났습니다!"));
  2503. break;
  2504. default:
  2505. if (item_gets[i])
  2506. {
  2507. if (dwCounts[i] > 1)
  2508. ChatInfoTrans(("상자에서 %s 가 %d 개 나왔습니다."), item_gets[i]->GetLocaleName(this), dwCounts[i]);
  2509. else
  2510. ChatInfoTrans(("상자에서 %s 가 나왔습니다."), item_gets[i]->GetLocaleName(this));
  2511. }
  2512. }
  2513. }
  2514. }
  2515. else
  2516. {
  2517. ChatInfoTrans(("아무것도 얻을 수 없었습니다."));
  2518. return false;
  2519. }
  2520. }
  2521. break;
  2522.  
  2523. case ITEM_SKILLFORGET:
  2524. {
  2525. if (!item->GetSocket(0))
  2526. {
  2527. ITEM_MANAGER::instance().RemoveItem(item);
  2528. return false;
  2529. }
  2530.  
  2531. DWORD dwVnum = item->GetSocket(0);
  2532.  
  2533. if (SkillLevelDown(dwVnum))
  2534. {
  2535. ITEM_MANAGER::instance().RemoveItem(item);
  2536. ChatInfoTrans(("스킬 레벨을 내리는데 성공하였습니다."));
  2537. }
  2538. else
  2539. ChatInfoTrans(("스킬 레벨을 내릴 수 없습니다."));
  2540. }
  2541. break;
  2542.  
  2543. case ITEM_SKILLBOOK:
  2544. {
  2545. if (IsPolymorphed())
  2546. {
  2547. ChatInfoTrans(("변신중에는 책을 읽을수 없습니다."));
  2548. return false;
  2549. }
  2550.  
  2551. DWORD dwVnum = 0;
  2552.  
  2553. if (item->GetVnum() == 50300)
  2554. {
  2555. dwVnum = item->GetSocket(0);
  2556. }
  2557. else
  2558. {
  2559. // 새로운 수련서는 value 0 에 스킬 번호가 있으므로 그것을 사용.
  2560. dwVnum = item->GetValue(0);
  2561. }
  2562.  
  2563. if (0 == dwVnum)
  2564. {
  2565. ITEM_MANAGER::instance().RemoveItem(item);
  2566.  
  2567. return false;
  2568. }
  2569.  
  2570. if (true == LearnSkillByBook(dwVnum))
  2571. {
  2572. #ifdef ENABLE_BOOKS_STACKFIX
  2573. item->SetCount(item->GetCount() - 0);
  2574. #else
  2575. ITEM_MANAGER::instance().RemoveItem(item);
  2576. #endif
  2577.  
  2578. int iReadDelay = number(SKILLBOOK_DELAY_MIN, SKILLBOOK_DELAY_MAX);
  2579.  
  2580. if (distribution_test_server)
  2581. iReadDelay /= 3;
  2582.  
  2583. SetSkillNextReadTime(dwVnum, get_global_time() + iReadDelay);
  2584. }
  2585. }
  2586. break;
  2587.  
  2588. case ITEM_USE:
  2589. {
  2590. if (item->GetVnum() > 50800 && item->GetVnum() <= 50820)
  2591. {
  2592. if (test_server)
  2593. sys_log (0, "ADD addtional effect : vnum(%d) subtype(%d)", item->GetOriginalVnum(), item->GetSubType());
  2594.  
  2595. int affect_type = AFFECT_EXP_BONUS_EURO_FREE;
  2596. int apply_type = aApplyInfo[item->GetValue(0)].bPointType;
  2597. int apply_value = item->GetValue(2);
  2598. int apply_duration = item->GetValue(1);
  2599.  
  2600. switch (item->GetSubType())
  2601. {
  2602. case USE_ABILITY_UP:
  2603. if (FindAffect(affect_type, apply_type))
  2604. {
  2605. ChatInfoTrans(("이미 효과가 걸려 있습니다."));
  2606. return false;
  2607. }
  2608.  
  2609. {
  2610. switch (item->GetValue(0))
  2611. {
  2612. case APPLY_MOV_SPEED:
  2613. AddAffect(affect_type, apply_type, apply_value, AFF_MOV_SPEED_POTION, apply_duration, 0, true, true);
  2614. break;
  2615.  
  2616. case APPLY_ATT_SPEED:
  2617. AddAffect(affect_type, apply_type, apply_value, AFF_ATT_SPEED_POTION, apply_duration, 0, true, true);
  2618. break;
  2619.  
  2620. case APPLY_STR:
  2621. case APPLY_DEX:
  2622. case APPLY_CON:
  2623. case APPLY_INT:
  2624. case APPLY_CAST_SPEED:
  2625. case APPLY_RESIST_MAGIC:
  2626. case APPLY_ATT_GRADE_BONUS:
  2627. case APPLY_DEF_GRADE_BONUS:
  2628. AddAffect(affect_type, apply_type, apply_value, 0, apply_duration, 0, true, true);
  2629. break;
  2630. }
  2631. }
  2632.  
  2633. if (GetDungeon())
  2634. GetDungeon()->UsePotion(this);
  2635.  
  2636. if (GetWarMap())
  2637. GetWarMap()->UsePotion(this, item);
  2638.  
  2639. item->SetCount(item->GetCount() - 0);
  2640. break;
  2641.  
  2642. case USE_AFFECT :
  2643. {
  2644. if (FindAffect(AFFECT_EXP_BONUS_EURO_FREE, aApplyInfo[item->GetValue(1)].bPointType))
  2645. {
  2646. ChatInfoTrans(("이미 효과가 걸려 있습니다."));
  2647. }
  2648. else
  2649. {
  2650. AddAffect(AFFECT_EXP_BONUS_EURO_FREE, aApplyInfo[item->GetValue(1)].bPointType, item->GetValue(2), 0, item->GetValue(3), 0, false, true);
  2651. item->SetCount(item->GetCount() - 0);
  2652. }
  2653. }
  2654. break;
  2655.  
  2656. case USE_POTION_NODELAY:
  2657. {
  2658. if (CArenaManager::instance().IsArenaMap(GetMapIndex()) == true)
  2659. {
  2660. if (quest::CQuestManager::instance().GetEventFlag("arena_potion_limit") > 0)
  2661. {
  2662. ChatInfoTrans(("대련장에서 사용하실 수 없습니다."));
  2663. return false;
  2664. }
  2665.  
  2666. switch (item->GetVnum())
  2667. {
  2668. case 70020 :
  2669. case 71018 :
  2670. case 71019 :
  2671. case 71020 :
  2672. if (quest::CQuestManager::instance().GetEventFlag("arena_potion_limit_count") < 10000)
  2673. {
  2674. if (m_nPotionLimit <= 0)
  2675. {
  2676. ChatInfoTrans(("사용 제한량을 초과하였습니다."));
  2677. return false;
  2678. }
  2679. }
  2680. break;
  2681.  
  2682. default :
  2683. ChatInfoTrans(("대련장에서 사용하실 수 없습니다."));
  2684. return false;
  2685. break;
  2686. }
  2687. }
  2688.  
  2689. bool used = false;
  2690.  
  2691. if (item->GetValue(0) != 0) // HP 절대값 회복
  2692. {
  2693. if (GetHP() < GetMaxHP())
  2694. {
  2695. PointChange(POINT_HP, item->GetValue(0) * (100 + GetPoint(POINT_POTION_BONUS)) / 100);
  2696. EffectPacket(SE_HPUP_RED);
  2697. used = TRUE;
  2698. }
  2699. }
  2700.  
  2701. if (item->GetValue(1) != 0) // SP 절대값 회복
  2702. {
  2703. if (GetSP() < GetMaxSP())
  2704. {
  2705. PointChange(POINT_SP, item->GetValue(1) * (100 + GetPoint(POINT_POTION_BONUS)) / 100);
  2706. EffectPacket(SE_SPUP_BLUE);
  2707. used = TRUE;
  2708. }
  2709. }
  2710.  
  2711. if (item->GetValue(3) != 0) // HP % 회복
  2712. {
  2713. if (GetHP() < GetMaxHP())
  2714. {
  2715. PointChange(POINT_HP, item->GetValue(3) * GetMaxHP() / 100);
  2716. EffectPacket(SE_HPUP_RED);
  2717. used = TRUE;
  2718. }
  2719. }
  2720.  
  2721. if (item->GetValue(4) != 0) // SP % 회복
  2722. {
  2723. if (GetSP() < GetMaxSP())
  2724. {
  2725. PointChange(POINT_SP, item->GetValue(4) * GetMaxSP() / 100);
  2726. EffectPacket(SE_SPUP_BLUE);
  2727. used = TRUE;
  2728. }
  2729. }
  2730.  
  2731. if (used)
  2732. {
  2733. if (item->GetVnum() == 50085 || item->GetVnum() == 50086)
  2734. {
  2735. if (test_server)
  2736. ChatInfoTrans(("월병 또는 종자 를 사용하였습니다"));
  2737. SetUseSeedOrMoonBottleTime();
  2738. }
  2739. if (GetDungeon())
  2740. GetDungeon()->UsePotion(this);
  2741.  
  2742. if (GetWarMap())
  2743. GetWarMap()->UsePotion(this, item);
  2744.  
  2745. m_nPotionLimit--;
  2746.  
  2747. //RESTRICT_USE_SEED_OR_MOONBOTTLE
  2748. item->SetCount(item->GetCount() - 1);
  2749. //END_RESTRICT_USE_SEED_OR_MOONBOTTLE
  2750. }
  2751. }
  2752. break;
  2753. }
  2754.  
  2755. return true;
  2756. }
  2757.  
  2758.  
  2759. if (item->GetVnum() >= 27863 && item->GetVnum() <= 27883)
  2760. {
  2761. if (CArenaManager::instance().IsArenaMap(GetMapIndex()) == true)
  2762. {
  2763. ChatInfoTrans(("대련 중에는 이용할 수 없는 물품입니다."));
  2764. return false;
  2765. }
  2766. }
  2767.  
  2768. if (test_server)
  2769. {
  2770. sys_log (0, "USE_ITEM %s Type %d SubType %d vnum %d", item->GetLocaleName(this), item->GetType(), item->GetSubType(), item->GetOriginalVnum());
  2771. }
  2772.  
  2773. switch (item->GetSubType())
  2774. {
  2775. case USE_TIME_CHARGE_PER:
  2776. {
  2777. LPITEM pDestItem = GetItem(DestCell);
  2778. if (NULL == pDestItem)
  2779. {
  2780. return false;
  2781. }
  2782. // 우선 용혼석에 관해서만 하도록 한다.
  2783. if (pDestItem->IsDragonSoul())
  2784. {
  2785. int ret;
  2786. char buf[128];
  2787. if (item->GetVnum() == DRAGON_HEART_VNUM)
  2788. {
  2789. ret = pDestItem->GiveMoreTime_Per((float)item->GetSocket(ITEM_SOCKET_CHARGING_AMOUNT_IDX));
  2790. }
  2791. else
  2792. {
  2793. ret = pDestItem->GiveMoreTime_Per((float)item->GetValue(ITEM_VALUE_CHARGING_AMOUNT_IDX));
  2794. }
  2795. if (ret > 0)
  2796. {
  2797. if (item->GetVnum() == DRAGON_HEART_VNUM)
  2798. {
  2799. sprintf(buf, "Inc %ds by item{VN:%d SOC%d:%ld}", ret, item->GetVnum(), ITEM_SOCKET_CHARGING_AMOUNT_IDX, item->GetSocket(ITEM_SOCKET_CHARGING_AMOUNT_IDX));
  2800. }
  2801. else
  2802. {
  2803. sprintf(buf, "Inc %ds by item{VN:%d VAL%d:%ld}", ret, item->GetVnum(), ITEM_VALUE_CHARGING_AMOUNT_IDX, item->GetValue(ITEM_VALUE_CHARGING_AMOUNT_IDX));
  2804. }
  2805.  
  2806. ChatInfoTrans(("%d초 만큼 충전되었습니다."), ret);
  2807. item->SetCount(item->GetCount() - 0);
  2808. LogManager::instance().ItemLog(this, item, "DS_CHARGING_SUCCESS", buf);
  2809. return true;
  2810. }
  2811. else
  2812. {
  2813. if (item->GetVnum() == DRAGON_HEART_VNUM)
  2814. {
  2815. sprintf(buf, "No change by item{VN:%d SOC%d:%ld}", item->GetVnum(), ITEM_SOCKET_CHARGING_AMOUNT_IDX, item->GetSocket(ITEM_SOCKET_CHARGING_AMOUNT_IDX));
  2816. }
  2817. else
  2818. {
  2819. sprintf(buf, "No change by item{VN:%d VAL%d:%ld}", item->GetVnum(), ITEM_VALUE_CHARGING_AMOUNT_IDX, item->GetValue(ITEM_VALUE_CHARGING_AMOUNT_IDX));
  2820. }
  2821.  
  2822. ChatInfoTrans(("충전할 수 없습니다."));
  2823. LogManager::instance().ItemLog(this, item, "DS_CHARGING_FAILED", buf);
  2824. return false;
  2825. }
  2826. }
  2827. else
  2828. return false;
  2829. }
  2830. break;
  2831. case USE_TIME_CHARGE_FIX:
  2832. {
  2833. LPITEM pDestItem = GetItem(DestCell);
  2834. if (NULL == pDestItem)
  2835. {
  2836. return false;
  2837. }
  2838. // 우선 용혼석에 관해서만 하도록 한다.
  2839. if (pDestItem->IsDragonSoul())
  2840. {
  2841. int ret = pDestItem->GiveMoreTime_Fix(item->GetValue(ITEM_VALUE_CHARGING_AMOUNT_IDX));
  2842. char buf[128];
  2843. if (ret)
  2844. {
  2845. ChatInfoTrans(("%d초 만큼 충전되었습니다."), ret);
  2846. sprintf(buf, "Increase %ds by item{VN:%d VAL%d:%ld}", ret, item->GetVnum(), ITEM_VALUE_CHARGING_AMOUNT_IDX, item->GetValue(ITEM_VALUE_CHARGING_AMOUNT_IDX));
  2847. LogManager::instance().ItemLog(this, item, "DS_CHARGING_SUCCESS", buf);
  2848. item->SetCount(item->GetCount() - 0);
  2849. return true;
  2850. }
  2851. else
  2852. {
  2853. ChatInfoTrans(("충전할 수 없습니다."));
  2854. sprintf(buf, "No change by item{VN:%d VAL%d:%ld}", item->GetVnum(), ITEM_VALUE_CHARGING_AMOUNT_IDX, item->GetValue(ITEM_VALUE_CHARGING_AMOUNT_IDX));
  2855. LogManager::instance().ItemLog(this, item, "DS_CHARGING_FAILED", buf);
  2856. return false;
  2857. }
  2858. }
  2859. else
  2860. return false;
  2861. }
  2862. break;
  2863. case USE_SPECIAL:
  2864.  
  2865. switch (item->GetVnum())
  2866. {
  2867. case ITEM_NOG_POCKET:
  2868. {
  2869. if (FindAffect(AFFECT_NOG_ABILITY))
  2870. {
  2871. ChatInfoTrans(("이미 효과가 걸려 있습니다."));
  2872. return false;
  2873. }
  2874. long time = item->GetValue(0);
  2875. long valAttack = item->GetValue(1);
  2876. AddAffect(AFFECT_NOG_ABILITY, POINT_ATTBONUS_HUMAN, valAttack, AFF_NONE, time, 0, true, true);
  2877. item->SetCount(item->GetCount() - 1);
  2878. }
  2879. break;
  2880.  
  2881. case ITEM_RAMADAN_CANDY:
  2882. {
  2883. long time = item->GetValue(0);
  2884. long moveSpeedPer = item->GetValue(1);
  2885. long attPer = item->GetValue(2);
  2886. long expPer = item->GetValue(3);
  2887. AddAffect(AFFECT_RAMADAN_ABILITY, POINT_MOV_SPEED, moveSpeedPer, AFF_MOV_SPEED_POTION, time, 0, true, true);
  2888. AddAffect(AFFECT_RAMADAN_ABILITY, POINT_MALL_ATTBONUS, attPer, AFF_NONE, time, 0, true, true);
  2889. AddAffect(AFFECT_RAMADAN_ABILITY, POINT_MALL_EXPBONUS, expPer, AFF_NONE, time, 0, true, true);
  2890. item->SetCount(item->GetCount() - 0);
  2891. }
  2892. break;
  2893. case ITEM_MARRIAGE_RING:
  2894. {
  2895. marriage::TMarriage* pMarriage = marriage::CManager::instance().Get(GetPlayerID());
  2896. if (pMarriage)
  2897. {
  2898. if (pMarriage->ch1 != NULL)
  2899. {
  2900. if (CArenaManager::instance().IsArenaMap(pMarriage->ch1->GetMapIndex()) == true)
  2901. {
  2902. ChatInfoTrans(("대련 중에는 이용할 수 없는 물품입니다."));
  2903. break;
  2904. }
  2905. }
  2906.  
  2907. if (pMarriage->ch2 != NULL)
  2908. {
  2909. if (CArenaManager::instance().IsArenaMap(pMarriage->ch2->GetMapIndex()) == true)
  2910. {
  2911. ChatInfoTrans(("대련 중에는 이용할 수 없는 물품입니다."));
  2912. break;
  2913. }
  2914. }
  2915.  
  2916. WarpToPID(pMarriage->GetOther(GetPlayerID()));
  2917. }
  2918. else
  2919. ChatInfoTrans(("결혼 상태가 아니면 결혼반지를 사용할 수 없습니다."));
  2920. }
  2921. break;
  2922.  
  2923. case UNIQUE_ITEM_CAPE_OF_COURAGE:
  2924. case 70057:
  2925. case REWARD_BOX_UNIQUE_ITEM_CAPE_OF_COURAGE:
  2926. AggregateMonster();
  2927. item->SetCount(item->GetCount()-1);
  2928. break;
  2929. #ifdef ENABLE_RENAME_ALIGNMENT_SYSTEM
  2930. case ITEM_RENAME_ALIGNMENT:
  2931. ChatPacket(CHAT_TYPE_COMMAND, "OpenRenameAlignment");
  2932. break;
  2933. #endif
  2934.  
  2935. case 27003:
  2936. case 27006:
  2937. case 27102:
  2938. case 27105:
  2939. case 70024:
  2940. item->SetCount(item->GetCount()-0);
  2941. break;
  2942.  
  2943. case UNIQUE_ITEM_WHITE_FLAG:
  2944. ForgetMyAttacker();
  2945. item->SetCount(item->GetCount()-1);
  2946. break;
  2947.  
  2948. case UNIQUE_ITEM_TREASURE_BOX:
  2949. break;
  2950.  
  2951. case 30093:
  2952. case 30094:
  2953. case 30095:
  2954. case 30096:
  2955. // 복주머니
  2956. {
  2957. const int MAX_BAG_INFO = 26;
  2958. static struct LuckyBagInfo
  2959. {
  2960. DWORD count;
  2961. int prob;
  2962. DWORD vnum;
  2963. } b1[MAX_BAG_INFO] =
  2964. {
  2965. { 1000, 302, 1 },
  2966. { 10, 150, 27002 },
  2967. { 10, 75, 27003 },
  2968. { 10, 100, 27005 },
  2969. { 10, 50, 27006 },
  2970. { 10, 80, 27001 },
  2971. { 10, 50, 27002 },
  2972. { 10, 80, 27004 },
  2973. { 10, 50, 27005 },
  2974. { 1, 10, 50300 },
  2975. { 1, 6, 92 },
  2976. { 1, 2, 132 },
  2977. { 1, 6, 1052 },
  2978. { 1, 2, 1092 },
  2979. { 1, 6, 2082 },
  2980. { 1, 2, 2122 },
  2981. { 1, 6, 3082 },
  2982. { 1, 2, 3122 },
  2983. { 1, 6, 5052 },
  2984. { 1, 2, 5082 },
  2985. { 1, 6, 7082 },
  2986. { 1, 2, 7122 },
  2987. { 1, 1, 11282 },
  2988. { 1, 1, 11482 },
  2989. { 1, 1, 11682 },
  2990. { 1, 1, 11882 },
  2991. };
  2992.  
  2993. LuckyBagInfo * bi = NULL;
  2994. bi = b1;
  2995.  
  2996. int pct = number(1, 1000);
  2997.  
  2998. int i;
  2999. for (i=0;i<MAX_BAG_INFO;i++)
  3000. {
  3001. if (pct <= bi[i].prob)
  3002. break;
  3003. pct -= bi[i].prob;
  3004. }
  3005. if (i>=MAX_BAG_INFO)
  3006. return false;
  3007.  
  3008. if (bi[i].vnum == 50300)
  3009. {
  3010. // 스킬수련서는 특수하게 준다.
  3011. GiveRandomSkillBook();
  3012. }
  3013. else if (bi[i].vnum == 1)
  3014. {
  3015. PointChange(POINT_GOLD, 1000, true);
  3016. }
  3017. else
  3018. {
  3019. AutoGiveItem(bi[i].vnum, bi[i].count);
  3020. }
  3021. ITEM_MANAGER::instance().RemoveItem(item);
  3022. }
  3023. break;
  3024.  
  3025. case 95002:
  3026. {
  3027. if (GetConquerorLevel() == 30) // if the player is level 30 already, return.
  3028. {
  3029. ChatInfoTrans(("Ai atins deja nivelul 30 campion."));
  3030. return false;
  3031. }
  3032.  
  3033.  
  3034. if (GetConquerorLevel() >= 1 && GetConquerorLevel() <= 5)
  3035. {
  3036. if (!FindAffect(AFFECT_CONQUEROR_BONUS_1))
  3037. AddAffect(AFFECT_CONQUEROR_BONUS_1, POINT_MAX_HP, 1000, 0, INFINITE_AFFECT_DURATION, 0, true);
  3038. }
  3039.  
  3040. else if (GetConquerorLevel() >= 6 && GetConquerorLevel() <= 10)
  3041. {
  3042. if (!FindAffect(AFFECT_CONQUEROR_BONUS_2))
  3043. AddAffect(AFFECT_CONQUEROR_BONUS_2, POINT_CRITICAL_PCT, 5, 0, INFINITE_AFFECT_DURATION, 0, true);
  3044. }
  3045.  
  3046. else if (GetConquerorLevel() >= 11 && GetConquerorLevel() <= 15)
  3047. {
  3048. if (!FindAffect(AFFECT_CONQUEROR_BONUS_3))
  3049. AddAffect(AFFECT_CONQUEROR_BONUS_3, POINT_POISON_REDUCE, 10, 0, INFINITE_AFFECT_DURATION, 0, true);
  3050. }
  3051.  
  3052. else if (GetConquerorLevel() >= 16 && GetConquerorLevel() <= 20)
  3053. {
  3054. if (!FindAffect(AFFECT_CONQUEROR_BONUS_4))
  3055. AddAffect(AFFECT_CONQUEROR_BONUS_4, POINT_ATT_GRADE_BONUS, 15, 0, INFINITE_AFFECT_DURATION, 0, true);
  3056. }
  3057.  
  3058. else if (GetConquerorLevel() >= 21 && GetConquerorLevel() <= 25)
  3059. {
  3060. if (!FindAffect(AFFECT_CONQUEROR_BONUS_5))
  3061. AddAffect(AFFECT_CONQUEROR_BONUS_5, POINT_ATTBONUS_HUMAN, 10, 0, INFINITE_AFFECT_DURATION, 0, true);
  3062. }
  3063.  
  3064. else if (GetConquerorLevel() >= 26 && GetConquerorLevel() <= 30)
  3065. {
  3066. if (!FindAffect(AFFECT_CONQUEROR_BONUS_6))
  3067. AddAffect(AFFECT_CONQUEROR_BONUS_6, POINT_SKILL_DAMAGE_BONUS, 5, 0, INFINITE_AFFECT_DURATION, 0, true);
  3068. }
  3069.  
  3070. SetConquerorLevel(GetConquerorLevel() + 5); // set the player conqueror level with his level and +5 points
  3071. ChatInfoTrans(("Ai primit 5 nivele campion.")); // notify the player about the level status
  3072. item->SetCount(item->GetCount() -1); // remove the item from the player after use
  3073.  
  3074. // Refresh Level State
  3075. ComputePoints();
  3076. PointsPacket();
  3077. UpdatePacket();
  3078. }
  3079. break;
  3080.  
  3081. case 95003:
  3082. {
  3083. if (GetConquerorLevel() == 30) // if the player is level 30 already, return.
  3084. {
  3085. ChatInfoTrans(("Ai atins deja nivelul 30 campion."));
  3086. return false;
  3087. }
  3088.  
  3089. if (!FindAffect(AFFECT_CONQUEROR_BONUS_1))
  3090. AddAffect(AFFECT_CONQUEROR_BONUS_1, POINT_MAX_HP, 1000, 0, INFINITE_AFFECT_DURATION, 0, true);
  3091. if (!FindAffect(AFFECT_CONQUEROR_BONUS_2))
  3092. AddAffect(AFFECT_CONQUEROR_BONUS_2, POINT_CRITICAL_PCT, 5, 0, INFINITE_AFFECT_DURATION, 0, true);
  3093. if (!FindAffect(AFFECT_CONQUEROR_BONUS_3))
  3094. AddAffect(AFFECT_CONQUEROR_BONUS_3, POINT_POISON_REDUCE, 10, 0, INFINITE_AFFECT_DURATION, 0, true);
  3095. if (!FindAffect(AFFECT_CONQUEROR_BONUS_4))
  3096. AddAffect(AFFECT_CONQUEROR_BONUS_4, POINT_ATT_GRADE_BONUS, 15, 0, INFINITE_AFFECT_DURATION, 0, true);
  3097. if (!FindAffect(AFFECT_CONQUEROR_BONUS_5))
  3098. AddAffect(AFFECT_CONQUEROR_BONUS_5, POINT_ATTBONUS_HUMAN, 10, 0, INFINITE_AFFECT_DURATION, 0, true);
  3099. if (!FindAffect(AFFECT_CONQUEROR_BONUS_6))
  3100. AddAffect(AFFECT_CONQUEROR_BONUS_6, POINT_SKILL_DAMAGE_BONUS, 5, 0, INFINITE_AFFECT_DURATION, 0, true);
  3101. ChatInfoTrans(("Ai primit toate bonusurile specifice nivelului maxim campion.")); // notify the player about the affect status
  3102.  
  3103. SetConquerorLevel(30); // set the player conqueror level to 30
  3104. ChatInfoTrans(("Ai atins nivelul 30 campion.")); // notify the player about the level status
  3105. item->SetCount(item->GetCount() -1); // remove the item from the player after use
  3106.  
  3107. // Refresh Level State
  3108. ComputePoints();
  3109. PointsPacket();
  3110. UpdatePacket();
  3111. }
  3112. break;
  3113.  
  3114. case 50004:
  3115. {
  3116. if (item->GetSocket(0))
  3117. {
  3118. item->SetSocket(0, item->GetSocket(0) + 1);
  3119. }
  3120. else
  3121. {
  3122. // 처음 사용시
  3123. int iMapIndex = GetMapIndex();
  3124.  
  3125. PIXEL_POSITION pos;
  3126.  
  3127. if (SECTREE_MANAGER::instance().GetRandomLocation(iMapIndex, pos, 700))
  3128. {
  3129. item->SetSocket(0, 1);
  3130. item->SetSocket(1, pos.x);
  3131. item->SetSocket(2, pos.y);
  3132. }
  3133. else
  3134. {
  3135. ChatInfoTrans(("이 곳에선 이벤트용 감지기가 동작하지 않는것 같습니다."));
  3136. return false;
  3137. }
  3138. }
  3139.  
  3140. int dist = 0;
  3141. float distance = (DISTANCE_SQRT(GetX()-item->GetSocket(1), GetY()-item->GetSocket(2)));
  3142.  
  3143. if (distance < 1000.0f)
  3144. {
  3145. // 발견!
  3146. ChatInfoTrans(("이벤트용 감지기가 신비로운 빛을 내며 사라집니다."));
  3147.  
  3148. // 사용횟수에 따라 주는 아이템을 다르게 한다.
  3149. struct TEventStoneInfo
  3150. {
  3151. DWORD dwVnum;
  3152. int count;
  3153. int prob;
  3154. };
  3155. const int EVENT_STONE_MAX_INFO = 15;
  3156. TEventStoneInfo info_10[EVENT_STONE_MAX_INFO] =
  3157. {
  3158. { 27001, 10, 8 },
  3159. { 27004, 10, 6 },
  3160. { 27002, 10, 12 },
  3161. { 27005, 10, 12 },
  3162. { 27100, 1, 9 },
  3163. { 27103, 1, 9 },
  3164. { 27101, 1, 10 },
  3165. { 27104, 1, 10 },
  3166. { 27999, 1, 12 },
  3167.  
  3168. { 25040, 1, 4 },
  3169.  
  3170. { 27410, 1, 0 },
  3171. { 27600, 1, 0 },
  3172. { 25100, 1, 0 },
  3173.  
  3174. { 50001, 1, 0 },
  3175. { 50003, 1, 1 },
  3176. };
  3177. TEventStoneInfo info_7[EVENT_STONE_MAX_INFO] =
  3178. {
  3179. { 27001, 10, 1 },
  3180. { 27004, 10, 1 },
  3181. { 27004, 10, 9 },
  3182. { 27005, 10, 9 },
  3183. { 27100, 1, 5 },
  3184. { 27103, 1, 5 },
  3185. { 27101, 1, 10 },
  3186. { 27104, 1, 10 },
  3187. { 27999, 1, 14 },
  3188.  
  3189. { 25040, 1, 5 },
  3190.  
  3191. { 27410, 1, 5 },
  3192. { 27600, 1, 5 },
  3193. { 25100, 1, 5 },
  3194.  
  3195. { 50001, 1, 0 },
  3196. { 50003, 1, 5 },
  3197.  
  3198. };
  3199. TEventStoneInfo info_4[EVENT_STONE_MAX_INFO] =
  3200. {
  3201. { 27001, 10, 0 },
  3202. { 27004, 10, 0 },
  3203. { 27002, 10, 0 },
  3204. { 27005, 10, 0 },
  3205. { 27100, 1, 0 },
  3206. { 27103, 1, 0 },
  3207. { 27101, 1, 0 },
  3208. { 27104, 1, 0 },
  3209. { 27999, 1, 25 },
  3210.  
  3211. { 25040, 1, 0 },
  3212.  
  3213. { 27410, 1, 0 },
  3214. { 27600, 1, 0 },
  3215. { 25100, 1, 15 },
  3216.  
  3217. { 50001, 1, 10 },
  3218. { 50003, 1, 50 },
  3219.  
  3220. };
  3221.  
  3222. {
  3223. TEventStoneInfo* info;
  3224. if (item->GetSocket(0) <= 4)
  3225. info = info_4;
  3226. else if (item->GetSocket(0) <= 7)
  3227. info = info_7;
  3228. else
  3229. info = info_10;
  3230.  
  3231. int prob = number(1, 100);
  3232.  
  3233. for (int i = 0; i < EVENT_STONE_MAX_INFO; ++i)
  3234. {
  3235. if (!info[i].prob)
  3236. continue;
  3237.  
  3238. if (prob <= info[i].prob)
  3239. {
  3240. if (info[i].dwVnum == 50001)
  3241. {
  3242. DWORD * pdw = M2_NEW DWORD[2];
  3243.  
  3244. pdw[0] = info[i].dwVnum;
  3245. pdw[1] = info[i].count;
  3246.  
  3247. // 추첨서는 소켓을 설정한다
  3248. DBManager::instance().ReturnQuery(QID_LOTTO, GetPlayerID(), pdw,
  3249. "INSERT INTO lotto_list VALUES(0, 'server%s', %u, NOW())",
  3250. get_table_postfix(), GetPlayerID());
  3251. }
  3252. else
  3253. AutoGiveItem(info[i].dwVnum, info[i].count);
  3254.  
  3255. break;
  3256. }
  3257. prob -= info[i].prob;
  3258. }
  3259. }
  3260.  
  3261. char chatbuf[CHAT_MAX_LEN + 1];
  3262. int len = snprintf(chatbuf, sizeof(chatbuf), "StoneDetect %u 0 0", (DWORD)GetVID());
  3263.  
  3264. if (len < 0 || len >= (int) sizeof(chatbuf))
  3265. len = sizeof(chatbuf) - 1;
  3266.  
  3267. ++len; // \0 문자까지 보내기
  3268.  
  3269. TPacketGCChat pack_chat;
  3270. pack_chat.header = HEADER_GC_CHAT;
  3271. pack_chat.size = sizeof(TPacketGCChat) + len;
  3272. pack_chat.type = CHAT_TYPE_COMMAND;
  3273. pack_chat.id = 0;
  3274. pack_chat.bEmpire = GetDesc()->GetEmpire();
  3275. //pack_chat.id = vid;
  3276.  
  3277. TEMP_BUFFER buf;
  3278. buf.write(&pack_chat, sizeof(TPacketGCChat));
  3279. buf.write(chatbuf, len);
  3280.  
  3281. PacketAround(buf.read_peek(), buf.size());
  3282.  
  3283. ITEM_MANAGER::instance().RemoveItem(item, "REMOVE (DETECT_EVENT_STONE) 1");
  3284. return true;
  3285. }
  3286. else if (distance < 20000)
  3287. dist = 1;
  3288. else if (distance < 70000)
  3289. dist = 2;
  3290. else
  3291. dist = 3;
  3292.  
  3293. // 많이 사용했으면 사라진다.
  3294. const int STONE_DETECT_MAX_TRY = 10;
  3295. if (item->GetSocket(0) >= STONE_DETECT_MAX_TRY)
  3296. {
  3297. ChatInfoTrans(("이벤트용 감지기가 흔적도 없이 사라집니다."));
  3298. ITEM_MANAGER::instance().RemoveItem(item, "REMOVE (DETECT_EVENT_STONE) 0");
  3299. AutoGiveItem(27002);
  3300. return true;
  3301. }
  3302.  
  3303. if (dist)
  3304. {
  3305. char chatbuf[CHAT_MAX_LEN + 1];
  3306. int len = snprintf(chatbuf, sizeof(chatbuf),
  3307. "StoneDetect %u %d %d",
  3308. (DWORD)GetVID(), dist, (int)GetDegreeFromPositionXY(GetX(), item->GetSocket(2), item->GetSocket(1), GetY()));
  3309.  
  3310. if (len < 0 || len >= (int) sizeof(chatbuf))
  3311. len = sizeof(chatbuf) - 1;
  3312.  
  3313. ++len; // \0 문자까지 보내기
  3314.  
  3315. TPacketGCChat pack_chat;
  3316. pack_chat.header = HEADER_GC_CHAT;
  3317. pack_chat.size = sizeof(TPacketGCChat) + len;
  3318. pack_chat.type = CHAT_TYPE_COMMAND;
  3319. pack_chat.id = 0;
  3320. pack_chat.bEmpire = GetDesc()->GetEmpire();
  3321. //pack_chat.id = vid;
  3322.  
  3323. TEMP_BUFFER buf;
  3324. buf.write(&pack_chat, sizeof(TPacketGCChat));
  3325. buf.write(chatbuf, len);
  3326.  
  3327. PacketAround(buf.read_peek(), buf.size());
  3328. }
  3329.  
  3330. }
  3331. break;
  3332.  
  3333. case 27989: // 영석감지기
  3334. case 76006: // 선물용 영석감지기
  3335. {
  3336. LPSECTREE_MAP pMap = SECTREE_MANAGER::instance().GetMap(GetMapIndex());
  3337.  
  3338. if (pMap != NULL)
  3339. {
  3340. item->SetSocket(0, item->GetSocket(0) + 1);
  3341.  
  3342. FFindStone f;
  3343.  
  3344. // <Factor> SECTREE::for_each -> SECTREE::for_each_entity
  3345. pMap->for_each(f);
  3346.  
  3347. if (f.m_mapStone.size() > 0)
  3348. {
  3349. std::map<DWORD, LPCHARACTER>::iterator stone = f.m_mapStone.begin();
  3350.  
  3351. DWORD max = UINT_MAX;
  3352. LPCHARACTER pTarget = stone->second;
  3353.  
  3354. while (stone != f.m_mapStone.end())
  3355. {
  3356. DWORD dist = (DWORD)DISTANCE_SQRT(GetX()-stone->second->GetX(), GetY()-stone->second->GetY());
  3357.  
  3358. if (dist != 0 && max > dist)
  3359. {
  3360. max = dist;
  3361. pTarget = stone->second;
  3362. }
  3363. stone++;
  3364. }
  3365.  
  3366. if (pTarget != NULL)
  3367. {
  3368. int val = 3;
  3369.  
  3370. if (max < 10000) val = 2;
  3371. else if (max < 70000) val = 1;
  3372.  
  3373. ChatPacket(CHAT_TYPE_COMMAND, "StoneDetect %u %d %d", (DWORD)GetVID(), val,
  3374. (int)GetDegreeFromPositionXY(GetX(), pTarget->GetY(), pTarget->GetX(), GetY()));
  3375. }
  3376. else
  3377. {
  3378. ChatInfoTrans(("감지기를 작용하였으나 감지되는 영석이 없습니다."));
  3379. }
  3380. }
  3381. else
  3382. {
  3383. ChatInfoTrans(("감지기를 작용하였으나 감지되는 영석이 없습니다."));
  3384. }
  3385.  
  3386. if (item->GetSocket(0) >= 6)
  3387. {
  3388. ChatPacket(CHAT_TYPE_COMMAND, "StoneDetect %u 0 0", (DWORD)GetVID());
  3389. ITEM_MANAGER::instance().RemoveItem(item);
  3390. }
  3391. }
  3392. break;
  3393. }
  3394. break;
  3395.  
  3396. case 27996: // 독병
  3397. item->SetCount(item->GetCount() - 0);
  3398. AttackedByPoison(NULL); // @warme008
  3399. break;
  3400.  
  3401. case 27987: // 조개
  3402. ChatInfoTrans(("말을 탄 상태에서 예복을 입을 수 없습니다."));
  3403. break;
  3404.  
  3405. case 71013: // 축제용폭죽
  3406. CreateFly(number(FLY_FIREWORK1, FLY_FIREWORK6), this);
  3407. item->SetCount(item->GetCount() - 0);
  3408. break;
  3409.  
  3410. case 50100: // 폭죽
  3411. case 50101:
  3412. case 50102:
  3413. case 50103:
  3414. case 50104:
  3415. case 50105:
  3416. case 50106:
  3417. CreateFly(item->GetVnum() - 50100 + FLY_FIREWORK1, this);
  3418. item->SetCount(item->GetCount() - 0);
  3419. break;
  3420.  
  3421. case 50200: // 보따리
  3422. if (GetMapIndex() == OXEVENT_MAP_INDEX || GetMapIndex() == 112 || GetMapIndex() >= 1100000 && GetMapIndex() <= 1110000)
  3423. return false;
  3424.  
  3425. if (g_bEnableBootaryCheck)
  3426. {
  3427. if (IS_BOTARYABLE_ZONE(GetMapIndex()) == true)
  3428. {
  3429. __OpenPrivateShop();
  3430. }
  3431. else
  3432. {
  3433. ChatInfoTrans(("개인 상점을 열 수 없는 지역입니다"));
  3434. }
  3435. }
  3436. else
  3437. {
  3438. __OpenPrivateShop();
  3439. }
  3440. break;
  3441.  
  3442. case fishing::FISH_MIND_PILL_VNUM:
  3443. AddAffect(AFFECT_FISH_MIND_PILL, POINT_NONE, 0, AFF_FISH_MIND, 20*60, 0, true);
  3444. item->SetCount(item->GetCount() - 0);
  3445. break;
  3446.  
  3447. case 50301: // 통솔력 수련서
  3448. case 50302:
  3449. case 50303:
  3450. {
  3451. if (IsPolymorphed() == true)
  3452. {
  3453. ChatInfoTrans(("둔갑 중에는 능력을 올릴 수 없습니다."));
  3454. return false;
  3455. }
  3456.  
  3457. int lv = GetSkillLevel(SKILL_LEADERSHIP);
  3458.  
  3459. if (lv < item->GetValue(0))
  3460. {
  3461. ChatInfoTrans(("이 책은 너무 어려워 이해하기가 힘듭니다."));
  3462. return false;
  3463. }
  3464.  
  3465. if (lv >= item->GetValue(1))
  3466. {
  3467. ChatInfoTrans(("이 책은 아무리 봐도 도움이 될 것 같지 않습니다."));
  3468. return false;
  3469. }
  3470.  
  3471. if (LearnSkillByBook(SKILL_LEADERSHIP))
  3472. {
  3473. #ifdef ENABLE_BOOKS_STACKFIX
  3474. item->SetCount(item->GetCount() - 0);
  3475. #else
  3476. ITEM_MANAGER::instance().RemoveItem(item);
  3477. #endif
  3478.  
  3479. int iReadDelay = number(SKILLBOOK_DELAY_MIN, SKILLBOOK_DELAY_MAX);
  3480. if (distribution_test_server) iReadDelay /= 3;
  3481.  
  3482. SetSkillNextReadTime(SKILL_LEADERSHIP, get_global_time() + iReadDelay);
  3483. }
  3484. }
  3485. break;
  3486.  
  3487. case 50304: // 연계기 수련서
  3488. case 50305:
  3489. case 50306:
  3490. {
  3491. if (IsPolymorphed())
  3492. {
  3493. ChatInfoTrans(("변신중에는 책을 읽을수 없습니다."));
  3494. return false;
  3495.  
  3496. }
  3497. if (GetSkillLevel(SKILL_COMBO) == 0 && GetLevel() < 30)
  3498. {
  3499. ChatInfoTrans(("레벨 30이 되기 전에는 습득할 수 있을 것 같지 않습니다."));
  3500. return false;
  3501. }
  3502.  
  3503. if (GetSkillLevel(SKILL_COMBO) == 1 && GetLevel() < 50)
  3504. {
  3505. ChatInfoTrans(("레벨 50이 되기 전에는 습득할 수 있을 것 같지 않습니다."));
  3506. return false;
  3507. }
  3508.  
  3509. if (GetSkillLevel(SKILL_COMBO) >= 2)
  3510. {
  3511. ChatInfoTrans(("연계기는 더이상 수련할 수 없습니다."));
  3512. return false;
  3513. }
  3514.  
  3515. int iPct = item->GetValue(0);
  3516.  
  3517. if (LearnSkillByBook(SKILL_COMBO, iPct))
  3518. {
  3519. #ifdef ENABLE_BOOKS_STACKFIX
  3520. item->SetCount(item->GetCount() - 0);
  3521. #else
  3522. ITEM_MANAGER::instance().RemoveItem(item);
  3523. #endif
  3524.  
  3525. int iReadDelay = number(SKILLBOOK_DELAY_MIN, SKILLBOOK_DELAY_MAX);
  3526. if (distribution_test_server) iReadDelay /= 3;
  3527.  
  3528. SetSkillNextReadTime(SKILL_COMBO, get_global_time() + iReadDelay);
  3529. }
  3530. }
  3531. break;
  3532. case 50311: // 언어 수련서
  3533. case 50312:
  3534. case 50313:
  3535. {
  3536. if (IsPolymorphed())
  3537. {
  3538. ChatInfoTrans(("변신중에는 책을 읽을수 없습니다."));
  3539. return false;
  3540.  
  3541. }
  3542. DWORD dwSkillVnum = item->GetValue(0);
  3543. int iPct = MINMAX(0, item->GetValue(1), 100);
  3544. if (GetSkillLevel(dwSkillVnum)>=20 || dwSkillVnum-SKILL_LANGUAGE1+1 == GetEmpire())
  3545. {
  3546. ChatInfoTrans(("이미 완벽하게 알아들을 수 있는 언어이다."));
  3547. return false;
  3548. }
  3549.  
  3550. if (LearnSkillByBook(dwSkillVnum, iPct))
  3551. {
  3552. #ifdef ENABLE_BOOKS_STACKFIX
  3553. item->SetCount(item->GetCount() - 0);
  3554. #else
  3555. ITEM_MANAGER::instance().RemoveItem(item);
  3556. #endif
  3557.  
  3558. int iReadDelay = number(SKILLBOOK_DELAY_MIN, SKILLBOOK_DELAY_MAX);
  3559. if (distribution_test_server) iReadDelay /= 3;
  3560.  
  3561. SetSkillNextReadTime(dwSkillVnum, get_global_time() + iReadDelay);
  3562. }
  3563. }
  3564. break;
  3565.  
  3566. case 50061 : // 일본 말 소환 스킬 수련서
  3567. {
  3568. if (IsPolymorphed())
  3569. {
  3570. ChatInfoTrans(("변신중에는 책을 읽을수 없습니다."));
  3571. return false;
  3572.  
  3573. }
  3574. DWORD dwSkillVnum = item->GetValue(0);
  3575. int iPct = MINMAX(0, item->GetValue(1), 100);
  3576.  
  3577. if (GetSkillLevel(dwSkillVnum) >= 10)
  3578. {
  3579. ChatInfoTrans(("더 이상 수련할 수 없습니다."));
  3580. return false;
  3581. }
  3582.  
  3583. if (LearnSkillByBook(dwSkillVnum, iPct))
  3584. {
  3585. #ifdef ENABLE_BOOKS_STACKFIX
  3586. item->SetCount(item->GetCount() - 0);
  3587. #else
  3588. ITEM_MANAGER::instance().RemoveItem(item);
  3589. #endif
  3590.  
  3591. int iReadDelay = number(SKILLBOOK_DELAY_MIN, SKILLBOOK_DELAY_MAX);
  3592. if (distribution_test_server) iReadDelay /= 3;
  3593.  
  3594. SetSkillNextReadTime(dwSkillVnum, get_global_time() + iReadDelay);
  3595. }
  3596. }
  3597. break;
  3598.  
  3599. case 50314: case 50315: case 50316: // 변신 수련서
  3600. case 50323: case 50324: // 증혈 수련서
  3601. case 50325: case 50326: // 철통 수련서
  3602. {
  3603. if (IsPolymorphed() == true)
  3604. {
  3605. ChatInfoTrans(("둔갑 중에는 능력을 올릴 수 없습니다."));
  3606. return false;
  3607. }
  3608.  
  3609. int iSkillLevelLowLimit = item->GetValue(0);
  3610. int iSkillLevelHighLimit = item->GetValue(1);
  3611. int iPct = MINMAX(0, item->GetValue(2), 100);
  3612. int iLevelLimit = item->GetValue(3);
  3613. DWORD dwSkillVnum = 0;
  3614.  
  3615. switch (item->GetVnum())
  3616. {
  3617. case 50314: case 50315: case 50316:
  3618. dwSkillVnum = SKILL_POLYMORPH;
  3619. break;
  3620.  
  3621. case 50323: case 50324:
  3622. dwSkillVnum = SKILL_ADD_HP;
  3623. break;
  3624.  
  3625. case 50325: case 50326:
  3626. dwSkillVnum = SKILL_RESIST_PENETRATE;
  3627. break;
  3628.  
  3629. default:
  3630. return false;
  3631. }
  3632.  
  3633. if (0 == dwSkillVnum)
  3634. return false;
  3635.  
  3636. if (GetLevel() < iLevelLimit)
  3637. {
  3638. ChatInfoTrans(("이 책을 읽으려면 레벨을 더 올려야 합니다."));
  3639. return false;
  3640. }
  3641.  
  3642. if (GetSkillLevel(dwSkillVnum) >= 40)
  3643. {
  3644. ChatInfoTrans(("더 이상 수련할 수 없습니다."));
  3645. return false;
  3646. }
  3647.  
  3648. if (GetSkillLevel(dwSkillVnum) < iSkillLevelLowLimit)
  3649. {
  3650. ChatInfoTrans(("이 책은 너무 어려워 이해하기가 힘듭니다."));
  3651. return false;
  3652. }
  3653.  
  3654. if (GetSkillLevel(dwSkillVnum) >= iSkillLevelHighLimit)
  3655. {
  3656. ChatInfoTrans(("이 책으로는 더 이상 수련할 수 없습니다."));
  3657. return false;
  3658. }
  3659.  
  3660. if (LearnSkillByBook(dwSkillVnum, iPct))
  3661. {
  3662. #ifdef ENABLE_BOOKS_STACKFIX
  3663. item->SetCount(item->GetCount() - 0);
  3664. #else
  3665. ITEM_MANAGER::instance().RemoveItem(item);
  3666. #endif
  3667.  
  3668. int iReadDelay = number(SKILLBOOK_DELAY_MIN, SKILLBOOK_DELAY_MAX);
  3669. if (distribution_test_server) iReadDelay /= 3;
  3670.  
  3671. SetSkillNextReadTime(dwSkillVnum, get_global_time() + iReadDelay);
  3672. }
  3673. }
  3674. break;
  3675.  
  3676. case 50902:
  3677. case 50903:
  3678. case 50904:
  3679. {
  3680. if (IsPolymorphed())
  3681. {
  3682. ChatInfoTrans(("변신중에는 책을 읽을수 없습니다."));
  3683. return false;
  3684.  
  3685. }
  3686. DWORD dwSkillVnum = SKILL_CREATE;
  3687. int iPct = MINMAX(0, item->GetValue(1), 100);
  3688.  
  3689. if (GetSkillLevel(dwSkillVnum)>=40)
  3690. {
  3691. ChatInfoTrans(("더 이상 수련할 수 없습니다."));
  3692. return false;
  3693. }
  3694.  
  3695. if (LearnSkillByBook(dwSkillVnum, iPct))
  3696. {
  3697. #ifdef ENABLE_BOOKS_STACKFIX
  3698. item->SetCount(item->GetCount() - 0);
  3699. #else
  3700. ITEM_MANAGER::instance().RemoveItem(item);
  3701. #endif
  3702.  
  3703. int iReadDelay = number(SKILLBOOK_DELAY_MIN, SKILLBOOK_DELAY_MAX);
  3704. if (distribution_test_server) iReadDelay /= 3;
  3705.  
  3706. SetSkillNextReadTime(dwSkillVnum, get_global_time() + iReadDelay);
  3707.  
  3708. if (test_server)
  3709. {
  3710. ChatPacket(CHAT_TYPE_INFO, "[TEST_SERVER] Success to learn skill ");
  3711. }
  3712. }
  3713. else
  3714. {
  3715. if (test_server)
  3716. {
  3717. ChatPacket(CHAT_TYPE_INFO, "[TEST_SERVER] Failed to learn skill ");
  3718. }
  3719. }
  3720. }
  3721. break;
  3722.  
  3723. // MINING
  3724. case ITEM_MINING_SKILL_TRAIN_BOOK:
  3725. {
  3726. if (IsPolymorphed())
  3727. {
  3728. ChatInfoTrans(("변신중에는 책을 읽을수 없습니다."));
  3729. return false;
  3730.  
  3731. }
  3732. DWORD dwSkillVnum = SKILL_MINING;
  3733. int iPct = MINMAX(0, item->GetValue(1), 100);
  3734.  
  3735. if (GetSkillLevel(dwSkillVnum)>=40)
  3736. {
  3737. ChatInfoTrans(("더 이상 수련할 수 없습니다."));
  3738. return false;
  3739. }
  3740.  
  3741. if (LearnSkillByBook(dwSkillVnum, iPct))
  3742. {
  3743. #ifdef ENABLE_BOOKS_STACKFIX
  3744. item->SetCount(item->GetCount() - 0);
  3745. #else
  3746. ITEM_MANAGER::instance().RemoveItem(item);
  3747. #endif
  3748.  
  3749. int iReadDelay = number(SKILLBOOK_DELAY_MIN, SKILLBOOK_DELAY_MAX);
  3750. if (distribution_test_server) iReadDelay /= 3;
  3751.  
  3752. SetSkillNextReadTime(dwSkillVnum, get_global_time() + iReadDelay);
  3753. }
  3754. }
  3755. break;
  3756. // END_OF_MINING
  3757.  
  3758. case ITEM_HORSE_SKILL_TRAIN_BOOK:
  3759. {
  3760. if (IsPolymorphed())
  3761. {
  3762. ChatInfoTrans(("변신중에는 책을 읽을수 없습니다."));
  3763. return false;
  3764.  
  3765. }
  3766. DWORD dwSkillVnum = SKILL_HORSE;
  3767. int iPct = MINMAX(0, item->GetValue(1), 100);
  3768.  
  3769. if (GetLevel() < 50)
  3770. {
  3771. ChatInfoTrans(("아직 승마 스킬을 수련할 수 있는 레벨이 아닙니다."));
  3772. return false;
  3773. }
  3774.  
  3775. if (!test_server && get_global_time() < GetSkillNextReadTime(dwSkillVnum))
  3776. {
  3777. if (FindAffect(AFFECT_SKILL_NO_BOOK_DELAY))
  3778. {
  3779. // 주안술서 사용중에는 시간 제한 무시
  3780. RemoveAffect(AFFECT_SKILL_NO_BOOK_DELAY);
  3781. ChatInfoTrans(("주안술서를 통해 주화입마에서 빠져나왔습니다."));
  3782. }
  3783. else
  3784. {
  3785. SkillLearnWaitMoreTimeMessage(GetSkillNextReadTime(dwSkillVnum) - get_global_time());
  3786. return false;
  3787. }
  3788. }
  3789.  
  3790. if (GetPoint(POINT_HORSE_SKILL) >= 20 ||
  3791. GetSkillLevel(SKILL_HORSE_WILDATTACK) + GetSkillLevel(SKILL_HORSE_CHARGE) + GetSkillLevel(SKILL_HORSE_ESCAPE) >= 60 ||
  3792. GetSkillLevel(SKILL_HORSE_WILDATTACK_RANGE) + GetSkillLevel(SKILL_HORSE_CHARGE) + GetSkillLevel(SKILL_HORSE_ESCAPE) >= 60)
  3793. {
  3794. ChatInfoTrans(("더 이상 승마 수련서를 읽을 수 없습니다."));
  3795. return false;
  3796. }
  3797.  
  3798. if (number(1, 100) <= iPct)
  3799. {
  3800. ChatInfoTrans(("승마 수련서를 읽어 승마 스킬 포인트를 얻었습니다."));
  3801. ChatInfoTrans(("얻은 포인트로는 승마 스킬의 레벨을 올릴 수 있습니다."));
  3802. PointChange(POINT_HORSE_SKILL, 1);
  3803.  
  3804. int iReadDelay = number(SKILLBOOK_DELAY_MIN, SKILLBOOK_DELAY_MAX);
  3805. if (distribution_test_server) iReadDelay /= 3;
  3806.  
  3807. if (!test_server)
  3808. SetSkillNextReadTime(dwSkillVnum, get_global_time() + iReadDelay);
  3809. }
  3810. else
  3811. {
  3812. ChatInfoTrans(("승마 수련서 이해에 실패하였습니다."));
  3813. }
  3814. #ifdef ENABLE_BOOKS_STACKFIX
  3815. item->SetCount(item->GetCount() - 0);
  3816. #else
  3817. ITEM_MANAGER::instance().RemoveItem(item);
  3818. #endif
  3819. }
  3820. break;
  3821.  
  3822. case 70102: // 선두
  3823. case 70103: // 선두
  3824. {
  3825. if (GetAlignment() >= 0)
  3826. return false;
  3827.  
  3828. int delta = MIN(-GetAlignment(), item->GetValue(0));
  3829.  
  3830. sys_log(0, "%s ALIGNMENT ITEM %d", GetStringName().c_str(), delta);
  3831.  
  3832. UpdateAlignment(delta);
  3833. item->SetCount(item->GetCount() - 0);
  3834.  
  3835. if (delta / 10 > 0)
  3836. {
  3837. ChatInfoTrans(("마음이 맑아지는군. 가슴을 짓누르던 무언가가 좀 가벼워진 느낌이야."));
  3838. ChatInfoTrans(("선악치가 %d 증가하였습니다."), delta/10);
  3839. }
  3840. }
  3841. break;
  3842.  
  3843. case 71107: // 천도복숭아
  3844. {
  3845. int val = item->GetValue(0);
  3846. int interval = item->GetValue(1);
  3847. quest::PC* pPC = quest::CQuestManager::instance().GetPC(GetPlayerID());
  3848. int last_use_time = pPC->GetFlag("mythical_peach.last_use_time");
  3849.  
  3850. if (get_global_time() - last_use_time < interval * 60 * 60)
  3851. {
  3852. if (test_server == false)
  3853. {
  3854. ChatInfoTrans(("아직 사용할 수 없습니다."));
  3855. return false;
  3856. }
  3857. else
  3858. {
  3859. ChatInfoTrans(("테스트 서버 시간제한 통과"));
  3860. }
  3861. }
  3862.  
  3863. if (GetAlignment() == 200000)
  3864. {
  3865. ChatInfoTrans(("선악치를 더 이상 올릴 수 없습니다."));
  3866. return false;
  3867. }
  3868.  
  3869. if (200000 - GetAlignment() < val * 10)
  3870. {
  3871. val = (200000 - GetAlignment()) / 10;
  3872. }
  3873.  
  3874. int old_alignment = GetAlignment() / 10;
  3875.  
  3876. UpdateAlignment(val*10);
  3877.  
  3878. item->SetCount(item->GetCount()-1);
  3879. pPC->SetFlag("mythical_peach.last_use_time", get_global_time());
  3880.  
  3881. ChatInfoTrans(("마음이 맑아지는군. 가슴을 짓누르던 무언가가 좀 가벼워진 느낌이야."));
  3882. ChatInfoTrans(("선악치가 %d 증가하였습니다."), val);
  3883.  
  3884. char buf[256 + 1];
  3885. snprintf(buf, sizeof(buf), "%d %d", old_alignment, GetAlignment() / 10);
  3886. LogManager::instance().CharLog(this, val, "MYTHICAL_PEACH", buf);
  3887. }
  3888. break;
  3889.  
  3890. case 71109: // 탈석서
  3891. case 72719:
  3892. {
  3893. LPITEM item2;
  3894.  
  3895. if (!IsValidItemPosition(DestCell) || !(item2 = GetItem(DestCell)))
  3896. return false;
  3897.  
  3898. if (item2->IsExchanging() || item2->IsEquipped()) // @fixme114
  3899. return false;
  3900.  
  3901. if (item2->GetSocketCount() == 0)
  3902. return false;
  3903.  
  3904. switch( item2->GetType() )
  3905. {
  3906. case ITEM_WEAPON:
  3907. break;
  3908. case ITEM_ARMOR:
  3909. switch (item2->GetSubType())
  3910. {
  3911. case ARMOR_EAR:
  3912. case ARMOR_WRIST:
  3913. case ARMOR_NECK:
  3914. ChatInfoTrans(("빼낼 영석이 없습니다"));
  3915. return false;
  3916. }
  3917. break;
  3918.  
  3919. default:
  3920. return false;
  3921. }
  3922.  
  3923. std::stack<long> socket;
  3924.  
  3925. for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
  3926. socket.push(item2->GetSocket(i));
  3927.  
  3928. int idx = ITEM_SOCKET_MAX_NUM - 1;
  3929.  
  3930. while (socket.size() > 0)
  3931. {
  3932. if (socket.top() > 2 && socket.top() != ITEM_BROKEN_METIN_VNUM)
  3933. break;
  3934.  
  3935. idx--;
  3936. socket.pop();
  3937. }
  3938.  
  3939. if (socket.size() == 0)
  3940. {
  3941. ChatInfoTrans(("빼낼 영석이 없습니다"));
  3942. return false;
  3943. }
  3944.  
  3945. LPITEM pItemReward = AutoGiveItem(socket.top());
  3946.  
  3947. if (pItemReward != NULL)
  3948. {
  3949. item2->SetSocket(idx, 1);
  3950.  
  3951. char buf[256+1];
  3952. snprintf(buf, sizeof(buf), "%s(%u) %s(%u)",
  3953. item2->GetLocaleName(this), item2->GetID(), pItemReward->GetLocaleName(this), pItemReward->GetID());
  3954. LogManager::instance().ItemLog(this, item, "USE_DETACHMENT_ONE", buf);
  3955.  
  3956. item->SetCount(item->GetCount() - 0);
  3957. }
  3958. }
  3959. break;
  3960.  
  3961. case 70201: // 탈색제
  3962. case 70202: // 염색약(흰색)
  3963. case 70203: // 염색약(금색)
  3964. case 70204: // 염색약(빨간색)
  3965. case 70205: // 염색약(갈색)
  3966. case 70206: // 염색약(검은색)
  3967. {
  3968. // NEW_HAIR_STYLE_ADD
  3969. if (GetPart(PART_HAIR) >= 1001)
  3970. {
  3971. ChatInfoTrans(("현재 헤어스타일에서는 염색과 탈색이 불가능합니다."));
  3972. }
  3973. // END_NEW_HAIR_STYLE_ADD
  3974. else
  3975. {
  3976. quest::CQuestManager& q = quest::CQuestManager::instance();
  3977. quest::PC* pPC = q.GetPC(GetPlayerID());
  3978.  
  3979. if (pPC)
  3980. {
  3981. int TimpColorant[] = {10};
  3982. if (GetQuestFlag("timer_colorant") && get_global_time() < GetQuestFlag("timer_colorant"))
  3983. {
  3984. ChatPacket(CHAT_TYPE_INFO, "Poti folosi in %d secunde.", (GetQuestFlag("timer_colorant") - get_global_time()) % 60);
  3985. return false;
  3986. }
  3987.  
  3988. int last_dye_level = pPC->GetFlag("dyeing_hair.last_dye_level");
  3989.  
  3990. if (last_dye_level == 0 ||
  3991. last_dye_level+3 <= GetLevel() ||
  3992. item->GetVnum() == 70201)
  3993. {
  3994. SetPart(PART_HAIR, item->GetVnum() - 70201);
  3995.  
  3996. if (item->GetVnum() == 70201)
  3997. pPC->SetFlag("dyeing_hair.last_dye_level", 0);
  3998. else
  3999. pPC->SetFlag("dyeing_hair.last_dye_level", GetLevel());
  4000.  
  4001. item->SetCount(item->GetCount() - 1);
  4002. UpdatePacket();
  4003. SetQuestFlag("timer_colorant", get_global_time() + TimpColorant[0]);
  4004. }
  4005. else
  4006. {
  4007. ChatInfoTrans(("%d 레벨이 되어야 다시 염색하실 수 있습니다."), last_dye_level+3);
  4008. }
  4009. }
  4010. }
  4011. }
  4012. break;
  4013.  
  4014. case ITEM_NEW_YEAR_GREETING_VNUM:
  4015. {
  4016. DWORD dwBoxVnum = ITEM_NEW_YEAR_GREETING_VNUM;
  4017. std::vector <DWORD> dwVnums;
  4018. std::vector <DWORD> dwCounts;
  4019. std::vector <LPITEM> item_gets;
  4020. int count = 0;
  4021.  
  4022. if (GiveItemFromSpecialItemGroup(dwBoxVnum, dwVnums, dwCounts, item_gets, count))
  4023. {
  4024. for (int i = 0; i < count; i++)
  4025. {
  4026. if (dwVnums[i] == CSpecialItemGroup::GOLD)
  4027. ChatInfoTrans(("돈 %d 냥을 획득했습니다."), dwCounts[i]);
  4028. }
  4029.  
  4030. item->SetCount(item->GetCount() - 0);
  4031. }
  4032. }
  4033. break;
  4034.  
  4035. case ITEM_VALENTINE_ROSE:
  4036. case ITEM_VALENTINE_CHOCOLATE:
  4037. {
  4038. DWORD dwBoxVnum = item->GetVnum();
  4039. std::vector <DWORD> dwVnums;
  4040. std::vector <DWORD> dwCounts;
  4041. std::vector <LPITEM> item_gets(0);
  4042. int count = 0;
  4043.  
  4044.  
  4045. if (((item->GetVnum() == ITEM_VALENTINE_ROSE) && (SEX_MALE==GET_SEX(this))) ||
  4046. ((item->GetVnum() == ITEM_VALENTINE_CHOCOLATE) && (SEX_FEMALE==GET_SEX(this))))
  4047. {
  4048. // 성별이 맞지않아 쓸 수 없다.
  4049. ChatInfoTrans(("성별이 맞지않아 이 아이템을 열 수 없습니다."));
  4050. return false;
  4051. }
  4052.  
  4053.  
  4054. if (GiveItemFromSpecialItemGroup(dwBoxVnum, dwVnums, dwCounts, item_gets, count))
  4055. item->SetCount(item->GetCount()-1);
  4056. }
  4057. break;
  4058.  
  4059. case ITEM_WHITEDAY_CANDY:
  4060. case ITEM_WHITEDAY_ROSE:
  4061. {
  4062. DWORD dwBoxVnum = item->GetVnum();
  4063. std::vector <DWORD> dwVnums;
  4064. std::vector <DWORD> dwCounts;
  4065. std::vector <LPITEM> item_gets(0);
  4066. int count = 0;
  4067.  
  4068.  
  4069. if (((item->GetVnum() == ITEM_WHITEDAY_CANDY) && (SEX_MALE==GET_SEX(this))) ||
  4070. ((item->GetVnum() == ITEM_WHITEDAY_ROSE) && (SEX_FEMALE==GET_SEX(this))))
  4071. {
  4072. // 성별이 맞지않아 쓸 수 없다.
  4073. ChatInfoTrans(("성별이 맞지않아 이 아이템을 열 수 없습니다."));
  4074. return false;
  4075. }
  4076.  
  4077.  
  4078. if (GiveItemFromSpecialItemGroup(dwBoxVnum, dwVnums, dwCounts, item_gets, count))
  4079. item->SetCount(item->GetCount()-1);
  4080. }
  4081. break;
  4082.  
  4083. case 50011: // 월광보합
  4084. {
  4085. DWORD dwBoxVnum = 50011;
  4086. std::vector <DWORD> dwVnums;
  4087. std::vector <DWORD> dwCounts;
  4088. std::vector <LPITEM> item_gets(0);
  4089. int count = 0;
  4090.  
  4091. if (GiveItemFromSpecialItemGroup(dwBoxVnum, dwVnums, dwCounts, item_gets, count))
  4092. {
  4093. for (int i = 0; i < count; i++)
  4094. {
  4095. char buf[50 + 1];
  4096. snprintf(buf, sizeof(buf), "%u %u", dwVnums[i], dwCounts[i]);
  4097. LogManager::instance().ItemLog(this, item, "MOONLIGHT_GET", buf);
  4098.  
  4099. //ITEM_MANAGER::instance().RemoveItem(item);
  4100. item->SetCount(item->GetCount() - 0);
  4101.  
  4102. switch (dwVnums[i])
  4103. {
  4104. case CSpecialItemGroup::GOLD:
  4105. ChatInfoTrans(("돈 %d 냥을 획득했습니다."), dwCounts[i]);
  4106. break;
  4107.  
  4108. case CSpecialItemGroup::EXP:
  4109. ChatInfoTrans(("상자에서 부터 신비한 빛이 나옵니다."));
  4110. ChatInfoTrans(("%d의 경험치를 획득했습니다."), dwCounts[i]);
  4111. break;
  4112.  
  4113. case CSpecialItemGroup::MOB:
  4114. ChatInfoTrans(("상자에서 몬스터가 나타났습니다!"));
  4115. break;
  4116.  
  4117. case CSpecialItemGroup::SLOW:
  4118. ChatInfoTrans(("상자에서 나온 빨간 연기를 들이마시자 움직이는 속도가 느려졌습니다!"));
  4119. break;
  4120.  
  4121. case CSpecialItemGroup::DRAIN_HP:
  4122. ChatInfoTrans(("상자가 갑자기 폭발하였습니다! 생명력이 감소했습니다."));
  4123. break;
  4124.  
  4125. case CSpecialItemGroup::POISON:
  4126. ChatInfoTrans(("상자에서 나온 녹색 연기를 들이마시자 독이 온몸으로 퍼집니다!"));
  4127. break;
  4128. #ifdef ENABLE_WOLFMAN_CHARACTER
  4129. case CSpecialItemGroup::BLEEDING:
  4130. ChatInfoTrans(("상자에서 나온 녹색 연기를 들이마시자 독이 온몸으로 퍼집니다!"));
  4131. break;
  4132. #endif
  4133. case CSpecialItemGroup::MOB_GROUP:
  4134. ChatInfoTrans(("상자에서 몬스터가 나타났습니다!"));
  4135. break;
  4136.  
  4137. default:
  4138. if (item_gets[i])
  4139. {
  4140. if (dwCounts[i] > 1)
  4141. ChatInfoTrans(("상자에서 %s 가 %d 개 나왔습니다."), item_gets[i]->GetLocaleName(this), dwCounts[i]);
  4142. else
  4143. ChatInfoTrans(("상자에서 %s 가 나왔습니다."), item_gets[i]->GetLocaleName(this));
  4144. }
  4145. break;
  4146. }
  4147. }
  4148. }
  4149. else
  4150. {
  4151. ChatInfoTrans(("아무것도 얻을 수 없었습니다."));
  4152. return false;
  4153. }
  4154. }
  4155. break;
  4156.  
  4157. case ITEM_GIVE_STAT_RESET_COUNT_VNUM:
  4158. {
  4159. //PointChange(POINT_GOLD, -iCost);
  4160. PointChange(POINT_STAT_RESET_COUNT, 1);
  4161. item->SetCount(item->GetCount()-1);
  4162. }
  4163. break;
  4164.  
  4165. case 50107:
  4166. {
  4167. if (CArenaManager::instance().IsArenaMap(GetMapIndex()) == true)
  4168. {
  4169. ChatInfoTrans(("대련 중에는 이용할 수 없는 물품입니다."));
  4170. return false;
  4171. }
  4172. EffectPacket(SE_CHINA_FIREWORK);
  4173. #ifdef ENABLE_FIREWORK_STUN
  4174. // 스턴 공격을 올려준다
  4175. AddAffect(AFFECT_CHINA_FIREWORK, POINT_STUN_PCT, 30, AFF_CHINA_FIREWORK, 5*60, 0, true);
  4176. #endif
  4177. item->SetCount(item->GetCount()-1);
  4178. }
  4179. break;
  4180.  
  4181. case 50108:
  4182. {
  4183. if (CArenaManager::instance().IsArenaMap(GetMapIndex()) == true)
  4184. {
  4185. ChatInfoTrans(("대련 중에는 이용할 수 없는 물품입니다."));
  4186. return false;
  4187. }
  4188. EffectPacket(SE_SPIN_TOP);
  4189. #ifdef ENABLE_FIREWORK_STUN
  4190. // 스턴 공격을 올려준다
  4191. AddAffect(AFFECT_CHINA_FIREWORK, POINT_STUN_PCT, 30, AFF_CHINA_FIREWORK, 5*60, 0, true);
  4192. #endif
  4193. item->SetCount(item->GetCount()-1);
  4194. }
  4195. break;
  4196.  
  4197. case ITEM_WONSO_BEAN_VNUM:
  4198. PointChange(POINT_HP, GetMaxHP() - GetHP());
  4199. item->SetCount(item->GetCount()-1);
  4200. break;
  4201.  
  4202. case ITEM_WONSO_SUGAR_VNUM:
  4203. PointChange(POINT_SP, GetMaxSP() - GetSP());
  4204. item->SetCount(item->GetCount()-1);
  4205. break;
  4206.  
  4207. case ITEM_WONSO_FRUIT_VNUM:
  4208. PointChange(POINT_STAMINA, GetMaxStamina()-GetStamina());
  4209. item->SetCount(item->GetCount()-1);
  4210. break;
  4211.  
  4212. case 90008: // VCARD
  4213. case 90009: // VCARD
  4214. VCardUse(this, this, item);
  4215. break;
  4216.  
  4217. case ITEM_ELK_VNUM: // 돈꾸러미
  4218. {
  4219. int iGold = item->GetSocket(0);
  4220. ITEM_MANAGER::instance().RemoveItem(item);
  4221. ChatInfoTrans(("돈 %d 냥을 획득했습니다."), iGold);
  4222. PointChange(POINT_GOLD, iGold);
  4223. }
  4224. break;
  4225. #ifdef __BATTLE_PASS__
  4226. case ITEM_BATTLE_PASS:
  4227. {
  4228. if (!v_counts.empty())
  4229. {
  4230. ChatPacket(CHAT_TYPE_INFO, "You have already one active!");
  4231. return false;
  4232. }
  4233.  
  4234. FILE *fileID;
  4235. char file_name[256+1];
  4236.  
  4237. snprintf(file_name, sizeof(file_name), "%s/battlepass_players/%s.txt", LocaleService_GetBasePath().c_str(),GetName());
  4238. fileID = fopen(file_name, "w");
  4239.  
  4240. if (NULL == fileID)
  4241. return false;
  4242.  
  4243. for (int i=0; i<missions_bp.size(); ++i)
  4244. {
  4245. fprintf(fileID,"MISSION %d %d\n", 0, 0);
  4246. }
  4247.  
  4248. fclose(fileID);
  4249.  
  4250. Load_BattlePass();
  4251. ChatPacket(CHAT_TYPE_INFO, "You activate battle pass for this month!");
  4252. item->SetCount(item->GetCount() - 1);
  4253. }
  4254. break;
  4255. #endif
  4256.  
  4257. //군주의 증표
  4258. case 27995:
  4259. {
  4260. }
  4261. break;
  4262.  
  4263. case 71092 : // 변신 해체부 임시
  4264. {
  4265. if (m_pkChrTarget != NULL)
  4266. {
  4267. if (m_pkChrTarget->IsPolymorphed())
  4268. {
  4269. m_pkChrTarget->SetPolymorph(0);
  4270. m_pkChrTarget->RemoveAffect(AFFECT_POLYMORPH);
  4271. }
  4272. }
  4273. else
  4274. {
  4275. if (IsPolymorphed())
  4276. {
  4277. SetPolymorph(0);
  4278. RemoveAffect(AFFECT_POLYMORPH);
  4279. }
  4280. }
  4281. }
  4282. break;
  4283.  
  4284. case 71051 : // 진재가
  4285. {
  4286. // 유럽, 싱가폴, 베트남 진재가 사용금지
  4287. LPITEM item2;
  4288.  
  4289. if (!IsValidItemPosition(DestCell) || !(item2 = GetInventoryItem(wDestCell)))
  4290. return false;
  4291.  
  4292. if (ITEM_COSTUME == item2->GetType()) // @fixme124
  4293. {
  4294. ChatInfoTrans(("속성을 변경할 수 없는 아이템입니다."));
  4295. return false;
  4296. }
  4297.  
  4298. if (item2->IsExchanging() || item2->IsEquipped()) // @fixme114
  4299. return false;
  4300.  
  4301. if (item2->GetAttributeSetIndex() == -1)
  4302. {
  4303. ChatInfoTrans(("속성을 변경할 수 없는 아이템입니다."));
  4304. return false;
  4305. }
  4306.  
  4307. if (item2->AddRareAttribute() == true)
  4308. {
  4309. ChatInfoTrans(("성공적으로 속성이 추가 되었습니다"));
  4310.  
  4311. int iAddedIdx = item2->GetRareAttrCount() + 4;
  4312. char buf[21];
  4313. snprintf(buf, sizeof(buf), "%u", item2->GetID());
  4314.  
  4315. LogManager::instance().ItemLog(
  4316. GetPlayerID(),
  4317. item2->GetAttributeType(iAddedIdx),
  4318. item2->GetAttributeValue(iAddedIdx),
  4319. item->GetID(),
  4320. "ADD_RARE_ATTR",
  4321. buf,
  4322. GetDesc()->GetHostName(),
  4323. item->GetOriginalVnum());
  4324.  
  4325. item->SetCount(item->GetCount() - 0);
  4326. }
  4327. else
  4328. {
  4329. ChatInfoTrans(("더 이상 이 아이템으로 속성을 추가할 수 없습니다"));
  4330. }
  4331. }
  4332. break;
  4333.  
  4334. case 71052 : // 진재경
  4335. {
  4336. // 유럽, 싱가폴, 베트남 진재가 사용금지
  4337. LPITEM item2;
  4338.  
  4339. if (!IsValidItemPosition(DestCell) || !(item2 = GetItem(DestCell)))
  4340. return false;
  4341.  
  4342. if (ITEM_COSTUME == item2->GetType()) // @fixme124
  4343. {
  4344. ChatInfoTrans(("속성을 변경할 수 없는 아이템입니다."));
  4345. return false;
  4346. }
  4347.  
  4348. if (item2->IsExchanging() || item2->IsEquipped()) // @fixme114
  4349. return false;
  4350.  
  4351. if (item2->GetAttributeSetIndex() == -1)
  4352. {
  4353. ChatInfoTrans(("속성을 변경할 수 없는 아이템입니다."));
  4354. return false;
  4355. }
  4356.  
  4357. if (item2->ChangeRareAttribute() == true)
  4358. {
  4359. char buf[21];
  4360. snprintf(buf, sizeof(buf), "%u", item2->GetID());
  4361. LogManager::instance().ItemLog(this, item, "CHANGE_RARE_ATTR", buf);
  4362.  
  4363. item->SetCount(item->GetCount() - 0);
  4364. }
  4365. else
  4366. {
  4367. ChatInfoTrans(("변경 시킬 속성이 없습니다"));
  4368. }
  4369. }
  4370. break;
  4371.  
  4372. case ITEM_AUTO_HP_RECOVERY_S:
  4373. case ITEM_AUTO_HP_RECOVERY_M:
  4374. case ITEM_AUTO_HP_RECOVERY_L:
  4375. case ITEM_AUTO_HP_RECOVERY_X:
  4376. case ITEM_AUTO_SP_RECOVERY_S:
  4377. case ITEM_AUTO_SP_RECOVERY_M:
  4378. case ITEM_AUTO_SP_RECOVERY_L:
  4379. case ITEM_AUTO_SP_RECOVERY_X:
  4380. // 무시무시하지만 이전에 하던 걸 고치기는 무섭고...
  4381. // 그래서 그냥 하드 코딩. 선물 상자용 자동물약 아이템들.
  4382. case REWARD_BOX_ITEM_AUTO_SP_RECOVERY_XS:
  4383. case REWARD_BOX_ITEM_AUTO_SP_RECOVERY_S:
  4384. case REWARD_BOX_ITEM_AUTO_HP_RECOVERY_XS:
  4385. case REWARD_BOX_ITEM_AUTO_HP_RECOVERY_S:
  4386. {
  4387. if (CArenaManager::instance().IsArenaMap(GetMapIndex()) == true)
  4388. {
  4389. ChatInfoTrans(("대련장에서 사용하실 수 없습니다."));
  4390. return false;
  4391. }
  4392.  
  4393. EAffectTypes type = AFFECT_NONE;
  4394.  
  4395. bool isSpecialPotion = false;
  4396.  
  4397. switch (item->GetVnum())
  4398. {
  4399. case ITEM_AUTO_HP_RECOVERY_X:
  4400. isSpecialPotion = true;
  4401.  
  4402. case ITEM_AUTO_HP_RECOVERY_S:
  4403. case ITEM_AUTO_HP_RECOVERY_M:
  4404. case ITEM_AUTO_HP_RECOVERY_L:
  4405. case REWARD_BOX_ITEM_AUTO_HP_RECOVERY_XS:
  4406. case REWARD_BOX_ITEM_AUTO_HP_RECOVERY_S:
  4407. type = AFFECT_AUTO_HP_RECOVERY;
  4408. break;
  4409.  
  4410. case ITEM_AUTO_SP_RECOVERY_X:
  4411. isSpecialPotion = true;
  4412.  
  4413. case ITEM_AUTO_SP_RECOVERY_S:
  4414. case ITEM_AUTO_SP_RECOVERY_M:
  4415. case ITEM_AUTO_SP_RECOVERY_L:
  4416. case REWARD_BOX_ITEM_AUTO_SP_RECOVERY_XS:
  4417. case REWARD_BOX_ITEM_AUTO_SP_RECOVERY_S:
  4418. type = AFFECT_AUTO_SP_RECOVERY;
  4419. break;
  4420. }
  4421.  
  4422. if (AFFECT_NONE == type)
  4423. break;
  4424.  
  4425. if (item->GetCount() > 1)
  4426. {
  4427. int pos = GetEmptyInventory(item->GetSize());
  4428.  
  4429. if (-1 == pos)
  4430. {
  4431. ChatInfoTrans(("소지품에 빈 공간이 없습니다."));
  4432. break;
  4433. }
  4434.  
  4435. item->SetCount( item->GetCount() - 0 );
  4436.  
  4437. LPITEM item2 = ITEM_MANAGER::instance().CreateItem( item->GetVnum(), 1 );
  4438. item2->AddToCharacter(this, TItemPos(INVENTORY, pos));
  4439.  
  4440. if (item->GetSocket(1) != 0)
  4441. {
  4442. item2->SetSocket(1, item->GetSocket(1));
  4443. }
  4444.  
  4445. item = item2;
  4446. }
  4447.  
  4448. CAffect* pAffect = FindAffect( type );
  4449.  
  4450. if (NULL == pAffect)
  4451. {
  4452. EPointTypes bonus = POINT_NONE;
  4453.  
  4454. if (true == isSpecialPotion)
  4455. {
  4456. if (type == AFFECT_AUTO_HP_RECOVERY)
  4457. {
  4458. bonus = POINT_MAX_HP_PCT;
  4459. }
  4460. else if (type == AFFECT_AUTO_SP_RECOVERY)
  4461. {
  4462. bonus = POINT_MAX_SP_PCT;
  4463. }
  4464. }
  4465.  
  4466. AddAffect( type, bonus, 4, item->GetID(), INFINITE_AFFECT_DURATION, 0, true, false);
  4467.  
  4468. item->Lock(true);
  4469. item->SetSocket(0, true);
  4470.  
  4471. AutoRecoveryItemProcess( type );
  4472. }
  4473. else
  4474. {
  4475. if (item->GetID() == pAffect->dwFlag)
  4476. {
  4477. RemoveAffect( pAffect );
  4478.  
  4479. item->Lock(false);
  4480. item->SetSocket(0, false);
  4481. }
  4482. else
  4483. {
  4484. LPITEM old = FindItemByID( pAffect->dwFlag );
  4485.  
  4486. if (NULL != old)
  4487. {
  4488. old->Lock(false);
  4489. old->SetSocket(0, false);
  4490. }
  4491.  
  4492. RemoveAffect( pAffect );
  4493.  
  4494. EPointTypes bonus = POINT_NONE;
  4495.  
  4496. if (true == isSpecialPotion)
  4497. {
  4498. if (type == AFFECT_AUTO_HP_RECOVERY)
  4499. {
  4500. bonus = POINT_MAX_HP_PCT;
  4501. }
  4502. else if (type == AFFECT_AUTO_SP_RECOVERY)
  4503. {
  4504. bonus = POINT_MAX_SP_PCT;
  4505. }
  4506. }
  4507.  
  4508. AddAffect( type, bonus, 4, item->GetID(), INFINITE_AFFECT_DURATION, 0, true, false);
  4509.  
  4510. item->Lock(true);
  4511. item->SetSocket(0, true);
  4512.  
  4513. AutoRecoveryItemProcess( type );
  4514. }
  4515. }
  4516. }
  4517. break;
  4518. }
  4519. break;
  4520.  
  4521. case USE_CLEAR:
  4522. {
  4523. switch (item->GetVnum())
  4524. {
  4525. #ifdef ENABLE_WOLFMAN_CHARACTER
  4526. case 27124: // Bandage
  4527. RemoveBleeding();
  4528. break;
  4529. #endif
  4530. case 27874: // Grilled Perch
  4531. default:
  4532. RemoveBadAffect();
  4533. break;
  4534. }
  4535. item->SetCount(item->GetCount() - 0);
  4536. }
  4537. break;
  4538.  
  4539. case USE_INVISIBILITY:
  4540. {
  4541. if (item->GetVnum() == 70026)
  4542. {
  4543. quest::CQuestManager& q = quest::CQuestManager::instance();
  4544. quest::PC* pPC = q.GetPC(GetPlayerID());
  4545.  
  4546. if (pPC != NULL)
  4547. {
  4548. int last_use_time = pPC->GetFlag("mirror_of_disapper.last_use_time");
  4549.  
  4550. if (get_global_time() - last_use_time < 10*60)
  4551. {
  4552. ChatInfoTrans(("아직 사용할 수 없습니다."));
  4553. return false;
  4554. }
  4555.  
  4556. pPC->SetFlag("mirror_of_disapper.last_use_time", get_global_time());
  4557. }
  4558. }
  4559.  
  4560. AddAffect(AFFECT_INVISIBILITY, POINT_NONE, 0, AFF_INVISIBILITY, 60, 0, true);
  4561. item->SetCount(item->GetCount() - 1);
  4562. }
  4563. break;
  4564.  
  4565. case USE_POTION_NODELAY:
  4566. {
  4567. if (CArenaManager::instance().IsArenaMap(GetMapIndex()) == true)
  4568. {
  4569. if (quest::CQuestManager::instance().GetEventFlag("arena_potion_limit") > 0)
  4570. {
  4571. ChatInfoTrans(("대련장에서 사용하실 수 없습니다."));
  4572. return false;
  4573. }
  4574.  
  4575. switch (item->GetVnum())
  4576. {
  4577. case 70020 :
  4578. case 71018 :
  4579. case 71019 :
  4580. case 71020 :
  4581. if (quest::CQuestManager::instance().GetEventFlag("arena_potion_limit_count") < 10000)
  4582. {
  4583. if (m_nPotionLimit <= 0)
  4584. {
  4585. ChatInfoTrans(("사용 제한량을 초과하였습니다."));
  4586. return false;
  4587. }
  4588. }
  4589. break;
  4590.  
  4591. default :
  4592. ChatInfoTrans(("대련장에서 사용하실 수 없습니다."));
  4593. return false;
  4594. }
  4595. }
  4596.  
  4597. bool used = false;
  4598.  
  4599. if (item->GetValue(0) != 0)
  4600. {
  4601. if (GetHP() < GetMaxHP())
  4602. {
  4603. PointChange(POINT_HP, item->GetValue(0) * (100 + GetPoint(POINT_POTION_BONUS)) / 100);
  4604. EffectPacket(SE_HPUP_RED);
  4605. used = TRUE;
  4606. }
  4607. }
  4608.  
  4609. if (item->GetValue(1) != 0)
  4610. {
  4611. if (GetSP() < GetMaxSP())
  4612. {
  4613. PointChange(POINT_SP, item->GetValue(1) * (100 + GetPoint(POINT_POTION_BONUS)) / 100);
  4614. EffectPacket(SE_SPUP_BLUE);
  4615. used = TRUE;
  4616. }
  4617. }
  4618.  
  4619. if (item->GetValue(3) != 0)
  4620. {
  4621. if (GetHP() < GetMaxHP())
  4622. {
  4623. PointChange(POINT_HP, item->GetValue(3) * GetMaxHP() / 100);
  4624. EffectPacket(SE_HPUP_RED);
  4625. used = TRUE;
  4626. }
  4627. }
  4628.  
  4629. if (item->GetValue(4) != 0)
  4630. {
  4631. if (GetSP() < GetMaxSP())
  4632. {
  4633. PointChange(POINT_SP, item->GetValue(4) * GetMaxSP() / 100);
  4634. EffectPacket(SE_SPUP_BLUE);
  4635. used = TRUE;
  4636. }
  4637. }
  4638.  
  4639. if (used)
  4640. {
  4641. if (item->GetVnum() == 50085 || item->GetVnum() == 50086)
  4642. {
  4643. if (test_server)
  4644. ChatInfoTrans(("월병 또는 종자 를 사용하였습니다"));
  4645. SetUseSeedOrMoonBottleTime();
  4646. }
  4647. if (GetDungeon())
  4648. GetDungeon()->UsePotion(this);
  4649.  
  4650. if (GetWarMap())
  4651. GetWarMap()->UsePotion(this, item);
  4652.  
  4653. m_nPotionLimit--;
  4654.  
  4655. item->SetCount(item->GetCount() - 1);
  4656. }
  4657. }
  4658. break;
  4659.  
  4660. case USE_POTION:
  4661. if (CArenaManager::instance().IsArenaMap(GetMapIndex()) == true)
  4662. {
  4663. if (quest::CQuestManager::instance().GetEventFlag("arena_potion_limit") > 0)
  4664. {
  4665. ChatInfoTrans(("대련장에서 사용하실 수 없습니다."));
  4666. return false;
  4667. }
  4668.  
  4669. switch (item->GetVnum())
  4670. {
  4671. case 27001 :
  4672. case 27002 :
  4673. case 27003 :
  4674. case 27004 :
  4675. case 27005 :
  4676. case 27006 :
  4677. if (quest::CQuestManager::instance().GetEventFlag("arena_potion_limit_count") < 10000)
  4678. {
  4679. if (m_nPotionLimit <= 0)
  4680. {
  4681. ChatInfoTrans(("사용 제한량을 초과하였습니다."));
  4682. return false;
  4683. }
  4684. }
  4685. break;
  4686. default :
  4687. ChatInfoTrans(("대련장에서 사용하실 수 없습니다."));
  4688. return false;
  4689. }
  4690. }
  4691.  
  4692. if (item->GetValue(1) != 0)
  4693. {
  4694. if (GetPoint(POINT_SP_RECOVERY) + GetSP() >= GetMaxSP())
  4695. {
  4696. return false;
  4697. }
  4698.  
  4699. PointChange(POINT_SP_RECOVERY, item->GetValue(1) * MIN(200, (100 + GetPoint(POINT_POTION_BONUS))) / 100);
  4700. StartAffectEvent();
  4701. EffectPacket(SE_SPUP_BLUE);
  4702. }
  4703.  
  4704. if (item->GetValue(0) != 0)
  4705. {
  4706. if (GetPoint(POINT_HP_RECOVERY) + GetHP() >= GetMaxHP())
  4707. {
  4708. return false;
  4709. }
  4710.  
  4711. PointChange(POINT_HP_RECOVERY, item->GetValue(0) * MIN(200, (100 + GetPoint(POINT_POTION_BONUS))) / 100);
  4712. StartAffectEvent();
  4713. EffectPacket(SE_HPUP_RED);
  4714. }
  4715.  
  4716. if (GetDungeon())
  4717. GetDungeon()->UsePotion(this);
  4718.  
  4719. if (GetWarMap())
  4720. GetWarMap()->UsePotion(this, item);
  4721. if (item->GetVnum() == 3591 || item->GetVnum() == 3592)
  4722. {
  4723. item->SetCount(item->GetCount() - 1);
  4724. }
  4725. else
  4726. {
  4727. item->SetCount(item->GetCount() - 0);
  4728. }
  4729. m_nPotionLimit--;
  4730. break;
  4731.  
  4732. case USE_POTION_CONTINUE:
  4733. {
  4734. if (item->GetValue(0) != 0)
  4735. {
  4736. AddAffect(AFFECT_HP_RECOVER_CONTINUE, POINT_HP_RECOVER_CONTINUE, item->GetValue(0), 0, item->GetValue(2), 0, true);
  4737. }
  4738. else if (item->GetValue(1) != 0)
  4739. {
  4740. AddAffect(AFFECT_SP_RECOVER_CONTINUE, POINT_SP_RECOVER_CONTINUE, item->GetValue(1), 0, item->GetValue(2), 0, true);
  4741. }
  4742. else
  4743. return false;
  4744. }
  4745.  
  4746. if (GetDungeon())
  4747. GetDungeon()->UsePotion(this);
  4748.  
  4749. if (GetWarMap())
  4750. GetWarMap()->UsePotion(this, item);
  4751.  
  4752. item->SetCount(item->GetCount() - 0);
  4753. break;
  4754.  
  4755. case USE_ABILITY_UP:
  4756. {
  4757. switch (item->GetValue(0))
  4758. {
  4759. case APPLY_MOV_SPEED:
  4760. if (FindAffect (AFFECT_MOV_SPEED))
  4761. {
  4762. ChatInfoTrans(("이미 효과가 걸려 있습니다."));
  4763. return false;
  4764. }
  4765. AddAffect(AFFECT_MOV_SPEED, POINT_MOV_SPEED, item->GetValue(2), AFF_MOV_SPEED_POTION, item->GetValue(1), 0, true);
  4766. #ifdef ENABLE_EFFECT_EXTRAPOT
  4767. EffectPacket(SE_DXUP_PURPLE);
  4768. #endif
  4769. break;
  4770.  
  4771. case APPLY_ATT_SPEED:
  4772. if (FindAffect (AFFECT_ATT_SPEED))
  4773. {
  4774. ChatInfoTrans(("이미 효과가 걸려 있습니다."));
  4775. return false;
  4776. }
  4777. AddAffect(AFFECT_ATT_SPEED, POINT_ATT_SPEED, item->GetValue(2), AFF_ATT_SPEED_POTION, item->GetValue(1), 0, true);
  4778. #ifdef ENABLE_EFFECT_EXTRAPOT
  4779. EffectPacket(SE_SPEEDUP_GREEN);
  4780. #endif
  4781. break;
  4782.  
  4783. case APPLY_STR:
  4784. AddAffect(AFFECT_STR, POINT_ST, item->GetValue(2), 0, item->GetValue(1), 0, true);
  4785. break;
  4786.  
  4787. case APPLY_DEX:
  4788. AddAffect(AFFECT_DEX, POINT_DX, item->GetValue(2), 0, item->GetValue(1), 0, true);
  4789. break;
  4790.  
  4791. case APPLY_CON:
  4792. AddAffect(AFFECT_CON, POINT_HT, item->GetValue(2), 0, item->GetValue(1), 0, true);
  4793. break;
  4794.  
  4795. case APPLY_INT:
  4796. AddAffect(AFFECT_INT, POINT_IQ, item->GetValue(2), 0, item->GetValue(1), 0, true);
  4797. break;
  4798.  
  4799. case APPLY_CAST_SPEED:
  4800. AddAffect(AFFECT_CAST_SPEED, POINT_CASTING_SPEED, item->GetValue(2), 0, item->GetValue(1), 0, true);
  4801. break;
  4802.  
  4803. case APPLY_ATT_GRADE_BONUS:
  4804. AddAffect(AFFECT_ATT_GRADE, POINT_ATT_GRADE_BONUS,
  4805. item->GetValue(2), 0, item->GetValue(1), 0, true);
  4806. break;
  4807.  
  4808. case APPLY_DEF_GRADE_BONUS:
  4809. AddAffect(AFFECT_DEF_GRADE, POINT_DEF_GRADE_BONUS,
  4810. item->GetValue(2), 0, item->GetValue(1), 0, true);
  4811. break;
  4812. }
  4813. }
  4814.  
  4815. if (GetDungeon())
  4816. GetDungeon()->UsePotion(this);
  4817.  
  4818. if (GetWarMap())
  4819. GetWarMap()->UsePotion(this, item);
  4820.  
  4821. item->SetCount(item->GetCount() - 0);
  4822. break;
  4823.  
  4824. case USE_TALISMAN:
  4825. {
  4826. const int TOWN_PORTAL = 1;
  4827. const int MEMORY_PORTAL = 2;
  4828.  
  4829.  
  4830. // gm_guild_build, oxevent 맵에서 귀환부 귀환기억부 를 사용못하게 막음
  4831. if (GetMapIndex() == 200 || GetMapIndex() == 113)
  4832. {
  4833. ChatInfoTrans(("현재 위치에서 사용할 수 없습니다."));
  4834. return false;
  4835. }
  4836.  
  4837. if (CArenaManager::instance().IsArenaMap(GetMapIndex()) == true)
  4838. {
  4839. ChatInfoTrans(("대련 중에는 이용할 수 없는 물품입니다."));
  4840. return false;
  4841. }
  4842.  
  4843. if (m_pkWarpEvent)
  4844. {
  4845. ChatInfoTrans(("이동할 준비가 되어있음으로 귀환부를 사용할수 없습니다"));
  4846. return false;
  4847. }
  4848.  
  4849. // CONSUME_LIFE_WHEN_USE_WARP_ITEM
  4850. int consumeLife = CalculateConsume(this);
  4851.  
  4852. if (consumeLife < 0)
  4853. return false;
  4854. // END_OF_CONSUME_LIFE_WHEN_USE_WARP_ITEM
  4855.  
  4856. if (item->GetValue(0) == TOWN_PORTAL) // 귀환부
  4857. {
  4858. if (item->GetSocket(0) == 0)
  4859. {
  4860. if (!GetDungeon())
  4861. if (!GiveRecallItem(item))
  4862. return false;
  4863.  
  4864. PIXEL_POSITION posWarp;
  4865.  
  4866. if (SECTREE_MANAGER::instance().GetRecallPositionByEmpire(GetMapIndex(), GetEmpire(), posWarp))
  4867. {
  4868. // CONSUME_LIFE_WHEN_USE_WARP_ITEM
  4869. PointChange(POINT_HP, -consumeLife, false);
  4870. // END_OF_CONSUME_LIFE_WHEN_USE_WARP_ITEM
  4871.  
  4872. WarpSet(posWarp.x, posWarp.y);
  4873. }
  4874. else
  4875. {
  4876. sys_err("CHARACTER::UseItem : cannot find spawn position (name %s, %d x %d)", GetStringName().c_str(), GetX(), GetY());
  4877. }
  4878. }
  4879. else
  4880. {
  4881. if (test_server)
  4882. ChatInfoTrans(("원래 위치로 복귀"));
  4883.  
  4884. ProcessRecallItem(item);
  4885. }
  4886. }
  4887. else if (item->GetValue(0) == MEMORY_PORTAL) // 귀환기억부
  4888. {
  4889. if (item->GetSocket(0) == 0)
  4890. {
  4891. if (GetDungeon())
  4892. {
  4893. ChatInfoTrans(("던전 안에서는 %s%s 사용할 수 없습니다."),
  4894. item->GetLocaleName(this),
  4895. "");
  4896. return false;
  4897. }
  4898.  
  4899. if (!GiveRecallItem(item))
  4900. return false;
  4901. }
  4902. else
  4903. {
  4904. // CONSUME_LIFE_WHEN_USE_WARP_ITEM
  4905. PointChange(POINT_HP, -consumeLife, false);
  4906. // END_OF_CONSUME_LIFE_WHEN_USE_WARP_ITEM
  4907.  
  4908. ProcessRecallItem(item);
  4909. }
  4910. }
  4911. }
  4912. break;
  4913.  
  4914. case USE_TUNING:
  4915. case USE_DETACHMENT:
  4916. {
  4917. LPITEM item2;
  4918.  
  4919. if (!IsValidItemPosition(DestCell) || !(item2 = GetItem(DestCell)))
  4920. return false;
  4921.  
  4922. if (item2->IsExchanging() || item2->IsEquipped()) // @fixme114
  4923. return false;
  4924.  
  4925. #ifdef __CHANGELOOK_SYSTEM__
  4926. if (item->GetValue(0) == CL_CLEAN_ATTR_VALUE0)
  4927. {
  4928. if (!CleanTransmutation(item, item2))
  4929. return false;
  4930. // item2->
  4931. // ChatInfoTrans(("Recieved %s from transmutation cleaning."), item2->GetTransmutation());
  4932. // AutoGiveItem(item2->GetTransmutation());
  4933.  
  4934. return true;
  4935. }
  4936. #endif
  4937.  
  4938. if (item2->GetVnum() >= 28330 && item2->GetVnum() <= 28343) // 영석+3
  4939. {
  4940. ChatInfoTrans(("+3 영석은 이 아이템으로 개량할 수 없습니다"));
  4941. return false;
  4942. }
  4943.  
  4944. if (item2->GetVnum() >= 28430 && item2->GetVnum() <= 28443) // 영석+4
  4945. {
  4946. if (item->GetVnum() == 71056) // 청룡의숨결
  4947. {
  4948. RefineItem(item, item2);
  4949. }
  4950. else
  4951. {
  4952. ChatInfoTrans(("영석은 이 아이템으로 개량할 수 없습니다"));
  4953. }
  4954. }
  4955. else
  4956. {
  4957. RefineItem(item, item2);
  4958. }
  4959. }
  4960. break;
  4961.  
  4962. // ACCESSORY_REFINE & ADD/CHANGE_ATTRIBUTES
  4963. case USE_PUT_INTO_BELT_SOCKET:
  4964. case USE_PUT_INTO_RING_SOCKET:
  4965. case USE_PUT_INTO_ACCESSORY_SOCKET:
  4966. case USE_ADD_ACCESSORY_SOCKET:
  4967. case USE_CLEAN_SOCKET:
  4968. case USE_CHANGE_ATTRIBUTE:
  4969. case USE_CHANGE_ATTRIBUTE2 :
  4970. case USE_ADD_ATTRIBUTE:
  4971. case USE_ADD_ATTRIBUTE2:
  4972. {
  4973. LPITEM item2;
  4974. if (!IsValidItemPosition(DestCell) || !(item2 = GetItem(DestCell)))
  4975. return false;
  4976.  
  4977. if (item2->IsEquipped())
  4978. {
  4979. BuffOnAttr_RemoveBuffsFromItem(item2);
  4980. }
  4981.  
  4982. // [NOTE] 코스튬 아이템에는 아이템 최초 생성시 랜덤 속성을 부여하되, 재경재가 등등은 막아달라는 요청이 있었음.
  4983. // 원래 ANTI_CHANGE_ATTRIBUTE 같은 아이템 Flag를 추가하여 기획 레벨에서 유연하게 컨트롤 할 수 있도록 할 예정이었으나
  4984. // 그딴거 필요없으니 닥치고 빨리 해달래서 그냥 여기서 막음... -_-
  4985. if (ITEM_COSTUME == item2->GetType())
  4986. {
  4987. ChatInfoTrans(("속성을 변경할 수 없는 아이템입니다."));
  4988. return false;
  4989. }
  4990.  
  4991. if (item2->IsExchanging() || item2->IsEquipped()) // @fixme114
  4992. return false;
  4993.  
  4994. switch (item->GetSubType())
  4995. {
  4996. case USE_CLEAN_SOCKET:
  4997. {
  4998. int i;
  4999. for (i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
  5000. {
  5001. if (item2->GetSocket(i) == ITEM_BROKEN_METIN_VNUM)
  5002. break;
  5003. }
  5004.  
  5005. if (i == ITEM_SOCKET_MAX_NUM)
  5006. {
  5007. ChatInfoTrans(("청소할 석이 박혀있지 않습니다."));
  5008. return false;
  5009. }
  5010.  
  5011. int j = 0;
  5012.  
  5013. for (i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
  5014. {
  5015. if (item2->GetSocket(i) != ITEM_BROKEN_METIN_VNUM && item2->GetSocket(i) != 0)
  5016. item2->SetSocket(j++, item2->GetSocket(i));
  5017. }
  5018.  
  5019. for (; j < ITEM_SOCKET_MAX_NUM; ++j)
  5020. {
  5021. if (item2->GetSocket(j) > 0)
  5022. item2->SetSocket(j, 1);
  5023. }
  5024.  
  5025. {
  5026. char buf[21];
  5027. snprintf(buf, sizeof(buf), "%u", item2->GetID());
  5028. LogManager::instance().ItemLog(this, item, "CLEAN_SOCKET", buf);
  5029. }
  5030.  
  5031. item->SetCount(item->GetCount() - 0);
  5032.  
  5033. }
  5034. break;
  5035.  
  5036. case USE_CHANGE_ATTRIBUTE :
  5037. case USE_CHANGE_ATTRIBUTE2 : // @fixme123
  5038. if (item2->GetAttributeSetIndex() == -1)
  5039. {
  5040. ChatInfoTrans(("속성을 변경할 수 없는 아이템입니다."));
  5041. return false;
  5042. }
  5043.  
  5044. if (item2->GetAttributeCount() == 0)
  5045. {
  5046. ChatInfoTrans(("변경할 속성이 없습니다."));
  5047. return false;
  5048. }
  5049.  
  5050. if ((GM_PLAYER == GetGMLevel()) && (false == test_server) && (g_dwItemBonusChangeTime > 0))
  5051. {
  5052. //
  5053. // Event Flag 를 통해 이전에 아이템 속성 변경을 한 시간으로 부터 충분한 시간이 흘렀는지 검사하고
  5054. // 시간이 충분히 흘렀다면 현재 속성변경에 대한 시간을 설정해 준다.
  5055. //
  5056.  
  5057. // DWORD dwChangeItemAttrCycle = quest::CQuestManager::instance().GetEventFlag(msc_szChangeItemAttrCycleFlag);
  5058. // if (dwChangeItemAttrCycle < msc_dwDefaultChangeItemAttrCycle)
  5059. // dwChangeItemAttrCycle = msc_dwDefaultChangeItemAttrCycle;
  5060. DWORD dwChangeItemAttrCycle = g_dwItemBonusChangeTime;
  5061.  
  5062. quest::PC* pPC = quest::CQuestManager::instance().GetPC(GetPlayerID());
  5063.  
  5064. if (pPC)
  5065. {
  5066. DWORD dwNowSec = get_global_time();
  5067.  
  5068. DWORD dwLastChangeItemAttrSec = pPC->GetFlag(msc_szLastChangeItemAttrFlag);
  5069.  
  5070. if (dwLastChangeItemAttrSec + dwChangeItemAttrCycle > dwNowSec)
  5071. {
  5072. ChatInfoTrans(("속성을 바꾼지 %d분 이내에는 다시 변경할 수 없습니다.(%d 분 남음)"),
  5073. dwChangeItemAttrCycle, dwChangeItemAttrCycle - (dwNowSec - dwLastChangeItemAttrSec));
  5074. return false;
  5075. }
  5076.  
  5077. pPC->SetFlag(msc_szLastChangeItemAttrFlag, dwNowSec);
  5078. }
  5079. }
  5080.  
  5081. if (item->GetSubType() == USE_CHANGE_ATTRIBUTE2)
  5082. {
  5083. int aiChangeProb[ITEM_ATTRIBUTE_MAX_LEVEL] =
  5084. {
  5085. 0, 0, 30, 40, 3
  5086. };
  5087.  
  5088. item2->ChangeAttribute(aiChangeProb);
  5089. }
  5090. else if (item->GetVnum() == 76014)
  5091. {
  5092. int aiChangeProb[ITEM_ATTRIBUTE_MAX_LEVEL] =
  5093. {
  5094. 0, 10, 50, 39, 1
  5095. };
  5096.  
  5097. item2->ChangeAttribute(aiChangeProb);
  5098. }
  5099.  
  5100. else
  5101. {
  5102. // 연재경 특수처리
  5103. // 절대로 연재가 추가 안될거라 하여 하드 코딩함.
  5104. if (item->GetVnum() == 71151 || item->GetVnum() == 76023)
  5105. {
  5106. if ((item2->GetType() == ITEM_WEAPON)
  5107. || (item2->GetType() == ITEM_ARMOR && item2->GetSubType() == ARMOR_BODY))
  5108. {
  5109. bool bCanUse = true;
  5110. for (int i = 0; i < ITEM_LIMIT_MAX_NUM; ++i)
  5111. {
  5112. if (item2->GetLimitType(i) == LIMIT_LEVEL && item2->GetLimitValue(i) > 40)
  5113. {
  5114. bCanUse = false;
  5115. break;
  5116. }
  5117. }
  5118. if (false == bCanUse)
  5119. {
  5120. ChatInfoTrans(("적용 레벨보다 높아 사용이 불가능합니다."));
  5121. break;
  5122. }
  5123. }
  5124. else
  5125. {
  5126. ChatInfoTrans(("무기와 갑옷에만 사용 가능합니다."));
  5127. break;
  5128. }
  5129. }
  5130. item2->ChangeAttribute();
  5131. }
  5132.  
  5133. // ChatInfoTrans(("속성을 변경하였습니다."));
  5134. {
  5135. char buf[21];
  5136. snprintf(buf, sizeof(buf), "%u", item2->GetID());
  5137. LogManager::instance().ItemLog(this, item, "CHANGE_ATTRIBUTE", buf);
  5138. }
  5139.  
  5140. item->SetCount(item->GetCount() - 0);
  5141. break;
  5142.  
  5143. case USE_ADD_ATTRIBUTE :
  5144. if (item2->GetAttributeSetIndex() == -1)
  5145. {
  5146. ChatInfoTrans(("속성을 변경할 수 없는 아이템입니다."));
  5147. return false;
  5148. }
  5149.  
  5150. if (item2->GetAttributeCount() < 4)
  5151. {
  5152. // 연재가 특수처리
  5153. // 절대로 연재가 추가 안될거라 하여 하드 코딩함.
  5154. if (item->GetVnum() == 71152 || item->GetVnum() == 76024)
  5155. {
  5156. if ((item2->GetType() == ITEM_WEAPON)
  5157. || (item2->GetType() == ITEM_ARMOR && item2->GetSubType() == ARMOR_BODY))
  5158. {
  5159. bool bCanUse = true;
  5160. for (int i = 0; i < ITEM_LIMIT_MAX_NUM; ++i)
  5161. {
  5162. if (item2->GetLimitType(i) == LIMIT_LEVEL && item2->GetLimitValue(i) > 40)
  5163. {
  5164. bCanUse = false;
  5165. break;
  5166. }
  5167. }
  5168. if (false == bCanUse)
  5169. {
  5170. ChatInfoTrans(("적용 레벨보다 높아 사용이 불가능합니다."));
  5171. break;
  5172. }
  5173. }
  5174. else
  5175. {
  5176. ChatInfoTrans(("무기와 갑옷에만 사용 가능합니다."));
  5177. break;
  5178. }
  5179. }
  5180. char buf[21];
  5181. snprintf(buf, sizeof(buf), "%u", item2->GetID());
  5182.  
  5183. if (number(1, 100) <= aiItemAttributeAddPercent[item2->GetAttributeCount()])
  5184. {
  5185.  
  5186. while (item2->GetAttributeCount() < 4)
  5187. item2->AddAttribute();
  5188. if (item2->GetAttributeCount() == 4)
  5189. item2->AddAttribute(); // 'bout 4 bns
  5190.  
  5191. ChatInfoTrans(("속성 추가에 성공하였습니다."));
  5192.  
  5193. int iAddedIdx = item2->GetAttributeCount() - 1;
  5194. LogManager::instance().ItemLog(
  5195. GetPlayerID(),
  5196. item2->GetAttributeType(iAddedIdx),
  5197. item2->GetAttributeValue(iAddedIdx),
  5198. item->GetID(),
  5199. "ADD_ATTRIBUTE_SUCCESS",
  5200. buf,
  5201. GetDesc()->GetHostName(),
  5202. item->GetOriginalVnum());
  5203. }
  5204. else
  5205. {
  5206. ChatInfoTrans(("속성 추가에 실패하였습니다."));
  5207. LogManager::instance().ItemLog(this, item, "ADD_ATTRIBUTE_FAIL", buf);
  5208. }
  5209.  
  5210. item->SetCount(item->GetCount() - 0);
  5211. }
  5212. else
  5213. {
  5214. ChatInfoTrans(("더이상 이 아이템을 이용하여 속성을 추가할 수 없습니다."));
  5215. }
  5216. break;
  5217.  
  5218.  
  5219. case USE_ADD_ATTRIBUTE2 :
  5220. // 축복의 구슬
  5221. // 재가비서를 통해 속성을 4개 추가 시킨 아이템에 대해서 하나의 속성을 더 붙여준다.
  5222. if (item2->GetAttributeSetIndex() == -1)
  5223. {
  5224. ChatInfoTrans(("속성을 변경할 수 없는 아이템입니다."));
  5225. return false;
  5226. }
  5227.  
  5228. // 속성이 이미 4개 추가 되었을 때만 속성을 추가 가능하다.
  5229. if (item2->GetAttributeCount() == 4)
  5230. {
  5231. if (item2->GetVnum() == 14149)
  5232. return false;
  5233.  
  5234. char buf[21];
  5235. snprintf(buf, sizeof(buf), "%u", item2->GetID());
  5236.  
  5237. if (number(1, 100) < 100)
  5238. {
  5239. item2->AddAttribute();
  5240. ChatInfoTrans(("속성 추가에 성공하였습니다."));
  5241.  
  5242. int iAddedIdx = item2->GetAttributeCount() - 0;
  5243. LogManager::instance().ItemLog(
  5244. GetPlayerID(),
  5245. item2->GetAttributeType(iAddedIdx),
  5246. item2->GetAttributeValue(iAddedIdx),
  5247. item->GetID(),
  5248. "ADD_ATTRIBUTE2_SUCCESS",
  5249. buf,
  5250. GetDesc()->GetHostName(),
  5251. item->GetOriginalVnum());
  5252. }
  5253. else
  5254. {
  5255. ChatInfoTrans(("속성 추가에 실패하였습니다."));
  5256. LogManager::instance().ItemLog(this, item, "ADD_ATTRIBUTE2_FAIL", buf);
  5257. }
  5258.  
  5259. item->SetCount(item->GetCount() - 0);
  5260. }
  5261. else if (item2->GetAttributeCount() == 5)
  5262. {
  5263. ChatInfoTrans(("더 이상 이 아이템을 이용하여 속성을 추가할 수 없습니다."));
  5264. }
  5265. else if (item2->GetAttributeCount() < 4)
  5266. {
  5267. ChatInfoTrans(("먼저 재가비서를 이용하여 속성을 추가시켜 주세요."));
  5268. }
  5269. else
  5270. {
  5271. // wtf ?!
  5272. sys_err("ADD_ATTRIBUTE2 : Item has wrong AttributeCount(%d)", item2->GetAttributeCount());
  5273. }
  5274. break;
  5275.  
  5276. case USE_ADD_ACCESSORY_SOCKET:
  5277. {
  5278. char buf[21];
  5279. snprintf(buf, sizeof(buf), "%u", item2->GetID());
  5280.  
  5281. if (item2->IsAccessoryForSocket())
  5282. {
  5283. if (item2->GetAccessorySocketMaxGrade() < ITEM_ACCESSORY_SOCKET_MAX_NUM)
  5284. {
  5285. #ifdef ENABLE_ADDSTONE_FAILURE
  5286. if (number(1, 100) <= 100)
  5287. #else
  5288. if (1)
  5289. #endif
  5290. {
  5291. item2->SetAccessorySocketMaxGrade(item2->GetAccessorySocketMaxGrade() + 1);
  5292. ChatInfoTrans(("소켓이 성공적으로 추가되었습니다."));
  5293. LogManager::instance().ItemLog(this, item, "ADD_SOCKET_SUCCESS", buf);
  5294. }
  5295. else
  5296. {
  5297. ChatInfoTrans(("소켓 추가에 실패하였습니다."));
  5298. LogManager::instance().ItemLog(this, item, "ADD_SOCKET_FAIL", buf);
  5299. }
  5300.  
  5301. item->SetCount(item->GetCount() - 0);
  5302. }
  5303. else
  5304. {
  5305. ChatInfoTrans(("이 액세서리에는 더이상 소켓을 추가할 공간이 없습니다."));
  5306. }
  5307. }
  5308. else
  5309. {
  5310. ChatInfoTrans(("이 아이템으로 소켓을 추가할 수 없는 아이템입니다."));
  5311. }
  5312. }
  5313. break;
  5314.  
  5315. case USE_PUT_INTO_BELT_SOCKET:
  5316. case USE_PUT_INTO_ACCESSORY_SOCKET:
  5317. if (item2->IsAccessoryForSocket() && item->CanPutInto(item2))
  5318. {
  5319. char buf[21];
  5320. snprintf(buf, sizeof(buf), "%u", item2->GetID());
  5321.  
  5322. if (item2->GetAccessorySocketGrade() < item2->GetAccessorySocketMaxGrade())
  5323. {
  5324. if (number(1, 100) <= aiAccessorySocketPutPct[item2->GetAccessorySocketGrade()])
  5325. {
  5326. item2->SetAccessorySocketGrade(item2->GetAccessorySocketGrade() + 1);
  5327. ChatInfoTrans(("장착에 성공하였습니다."));
  5328. LogManager::instance().ItemLog(this, item, "PUT_SOCKET_SUCCESS", buf);
  5329. }
  5330. else
  5331. {
  5332. ChatInfoTrans(("장착에 실패하였습니다."));
  5333. LogManager::instance().ItemLog(this, item, "PUT_SOCKET_FAIL", buf);
  5334. }
  5335.  
  5336. item->SetCount(item->GetCount() - 0);
  5337. }
  5338. else
  5339. {
  5340. if (item2->GetAccessorySocketMaxGrade() == 0)
  5341. ChatInfoTrans(("먼저 다이아몬드로 악세서리에 소켓을 추가해야합니다."));
  5342. else if (item2->GetAccessorySocketMaxGrade() < ITEM_ACCESSORY_SOCKET_MAX_NUM)
  5343. {
  5344. ChatInfoTrans(("이 액세서리에는 더이상 장착할 소켓이 없습니다."));
  5345. ChatInfoTrans(("다이아몬드로 소켓을 추가해야합니다."));
  5346. }
  5347. else
  5348. ChatInfoTrans(("이 액세서리에는 더이상 보석을 장착할 수 없습니다."));
  5349. }
  5350. }
  5351. else
  5352. {
  5353. ChatInfoTrans(("이 아이템을 장착할 수 없습니다."));
  5354. }
  5355. break;
  5356. }
  5357. if (item2->IsEquipped())
  5358. {
  5359. BuffOnAttr_AddBuffsFromItem(item2);
  5360. }
  5361. }
  5362. break;
  5363. // END_OF_ACCESSORY_REFINE & END_OF_ADD_ATTRIBUTES & END_OF_CHANGE_ATTRIBUTES
  5364.  
  5365. #ifdef ENABLE_AUTODESC_SYSTEM
  5366. case USE_ADD_AUTODESC:
  5367. {
  5368. LPITEM item2;
  5369.  
  5370. if (!IsValidItemPosition(DestCell) || !(item2 = GetItem(DestCell)))
  5371. return false;
  5372.  
  5373. if (item2->IsExchanging() || item2->IsEquipped())
  5374. return false;
  5375.  
  5376. // if (!IS_SET(item2->GetFlag(), ITEM_FLAG_DESCRIPTION))
  5377. // return false;
  5378.  
  5379. item->Lock(true);
  5380. item2->Lock(true);
  5381. TPacketGCAutoDesc packet;
  5382. packet.header = HEADER_GC_AUTODESC;
  5383. packet.iPos = item2->GetCell();
  5384. packet.bWindow = 0;
  5385. packet.iTicketPos = item->GetCell();
  5386. GetDesc()->Packet(&packet, sizeof(TPacketGCAutoDesc));
  5387. }
  5388. break;
  5389.  
  5390. case USE_REMOVE_AUTODESC:
  5391. {
  5392. LPITEM item2;
  5393.  
  5394. if (!IsValidItemPosition(DestCell) || !(item2 = GetItem(DestCell)))
  5395. return false;
  5396.  
  5397. if (item2->IsExchanging() || item2->IsEquipped())
  5398. return false;
  5399.  
  5400. // if (!IS_SET(item2->GetFlag(), ITEM_FLAG_DESCRIPTION))
  5401. // return false;
  5402.  
  5403. item->Lock(true);
  5404. item2->Lock(true);
  5405. TPacketGCAutoDesc packet;
  5406. packet.header = HEADER_GC_AUTODESC;
  5407. packet.iPos = item2->GetCell();
  5408. packet.bWindow = 1;
  5409. packet.iTicketPos = item->GetCell();
  5410. GetDesc()->Packet(&packet, sizeof(TPacketGCAutoDesc));
  5411. }
  5412. break;
  5413. #endif
  5414.  
  5415. case USE_BAIT:
  5416. {
  5417.  
  5418. if (m_pkFishingEvent)
  5419. {
  5420. ChatInfoTrans(("낚시 중에 미끼를 갈아끼울 수 없습니다."));
  5421. return false;
  5422. }
  5423.  
  5424. LPITEM weapon = GetWear(WEAR_WEAPON);
  5425.  
  5426. if (!weapon || weapon->GetType() != ITEM_ROD)
  5427. return false;
  5428.  
  5429. if (weapon->GetSocket(2))
  5430. {
  5431. ChatInfoTrans(("이미 꽂혀있던 미끼를 빼고 %s를 끼웁니다."), item->GetLocaleName(this));
  5432. }
  5433. else
  5434. {
  5435. ChatInfoTrans(("낚시대에 %s를 미끼로 끼웁니다."), item->GetLocaleName(this));
  5436. }
  5437.  
  5438. weapon->SetSocket(2, item->GetValue(0));
  5439. item->SetCount(item->GetCount() - 0);
  5440. }
  5441. break;
  5442.  
  5443. case USE_MOVE:
  5444. case USE_TREASURE_BOX:
  5445. case USE_MONEYBAG:
  5446. break;
  5447.  
  5448. case USE_AFFECT :
  5449. {
  5450. if (FindAffect(item->GetValue(0), aApplyInfo[item->GetValue(1)].bPointType))
  5451. {
  5452. ChatInfoTrans(("이미 효과가 걸려 있습니다."));
  5453. }
  5454. else
  5455. {
  5456. // PC_BANG_ITEM_ADD
  5457. if (item->IsPCBangItem() == true)
  5458. {
  5459. // PC방인지 체크해서 처리
  5460. if (CPCBangManager::instance().IsPCBangIP(GetDesc()->GetHostName()) == false)
  5461. {
  5462. // PC방이 아님!
  5463. ChatInfoTrans(("이 아이템은 PC방에서만 사용할 수 있습니다."));
  5464. return false;
  5465. }
  5466. }
  5467. // END_PC_BANG_ITEM_ADD
  5468.  
  5469. AddAffect(item->GetValue(0), aApplyInfo[item->GetValue(1)].bPointType, item->GetValue(2), 0, item->GetValue(3), 0, false);
  5470. item->SetCount(item->GetCount() - 0);
  5471. }
  5472. }
  5473. break;
  5474.  
  5475. case USE_CREATE_STONE:
  5476. AutoGiveItem(number(28000, 28013));
  5477. item->SetCount(item->GetCount() - 0);
  5478. break;
  5479.  
  5480. // 물약 제조 스킬용 레시피 처리
  5481. case USE_RECIPE :
  5482. {
  5483. LPITEM pSource1 = FindSpecifyItem(item->GetValue(1));
  5484. DWORD dwSourceCount1 = item->GetValue(2);
  5485.  
  5486. LPITEM pSource2 = FindSpecifyItem(item->GetValue(3));
  5487. DWORD dwSourceCount2 = item->GetValue(4);
  5488.  
  5489. if (dwSourceCount1 != 0)
  5490. {
  5491. if (pSource1 == NULL)
  5492. {
  5493. ChatInfoTrans(("물약 조합을 위한 재료가 부족합니다."));
  5494. return false;
  5495. }
  5496. }
  5497.  
  5498. if (dwSourceCount2 != 0)
  5499. {
  5500. if (pSource2 == NULL)
  5501. {
  5502. ChatInfoTrans(("물약 조합을 위한 재료가 부족합니다."));
  5503. return false;
  5504. }
  5505. }
  5506.  
  5507. if (pSource1 != NULL)
  5508. {
  5509. if (pSource1->GetCount() < dwSourceCount1)
  5510. {
  5511. ChatInfoTrans(("재료(%s)가 부족합니다."), pSource1->GetLocaleName(this));
  5512. return false;
  5513. }
  5514.  
  5515. pSource1->SetCount(pSource1->GetCount() - dwSourceCount1);
  5516. }
  5517.  
  5518. if (pSource2 != NULL)
  5519. {
  5520. if (pSource2->GetCount() < dwSourceCount2)
  5521. {
  5522. ChatInfoTrans(("재료(%s)가 부족합니다."), pSource2->GetLocaleName(this));
  5523. return false;
  5524. }
  5525.  
  5526. pSource2->SetCount(pSource2->GetCount() - dwSourceCount2);
  5527. }
  5528.  
  5529. LPITEM pBottle = FindSpecifyItem(50901);
  5530.  
  5531. if (!pBottle || pBottle->GetCount() < 1)
  5532. {
  5533. ChatInfoTrans(("빈 병이 모자릅니다."));
  5534. return false;
  5535. }
  5536.  
  5537. pBottle->SetCount(pBottle->GetCount() - 0);
  5538.  
  5539. if (number(1, 100) > item->GetValue(5))
  5540. {
  5541. ChatInfoTrans(("물약 제조에 실패했습니다."));
  5542. return false;
  5543. }
  5544.  
  5545. AutoGiveItem(item->GetValue(0));
  5546. }
  5547. break;
  5548. }
  5549. }
  5550. break;
  5551.  
  5552. case ITEM_METIN:
  5553. {
  5554. LPITEM item2;
  5555.  
  5556. if (!IsValidItemPosition(DestCell) || !(item2 = GetItem(DestCell)))
  5557. return false;
  5558.  
  5559. if (item2->IsExchanging() || item2->IsEquipped()) // @fixme114
  5560. return false;
  5561.  
  5562. if (item2->GetType() == ITEM_PICK) return false;
  5563. if (item2->GetType() == ITEM_ROD) return false;
  5564.  
  5565. int i;
  5566.  
  5567. for (i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
  5568. {
  5569. DWORD dwVnum;
  5570.  
  5571. if ((dwVnum = item2->GetSocket(i)) <= 2)
  5572. continue;
  5573.  
  5574. TItemTable * p = ITEM_MANAGER::instance().GetTable(dwVnum);
  5575.  
  5576. if (!p)
  5577. continue;
  5578.  
  5579. if (item->GetValue(5) == p->alValues[5])
  5580. {
  5581. ChatInfoTrans(("같은 종류의 메틴석은 여러개 부착할 수 없습니다."));
  5582. return false;
  5583. }
  5584. }
  5585.  
  5586. if (item2->GetType() == ITEM_ARMOR)
  5587. {
  5588. if (!IS_SET(item->GetWearFlag(), WEARABLE_BODY) || !IS_SET(item2->GetWearFlag(), WEARABLE_BODY))
  5589. {
  5590. ChatInfoTrans(("이 메틴석은 장비에 부착할 수 없습니다."));
  5591. return false;
  5592. }
  5593. }
  5594. else if (item2->GetType() == ITEM_WEAPON)
  5595. {
  5596. if (!IS_SET(item->GetWearFlag(), WEARABLE_WEAPON))
  5597. {
  5598. ChatInfoTrans(("이 메틴석은 무기에 부착할 수 없습니다."));
  5599. return false;
  5600. }
  5601. }
  5602. else
  5603. {
  5604. ChatInfoTrans(("부착할 수 있는 슬롯이 없습니다."));
  5605. return false;
  5606. }
  5607.  
  5608. for (i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
  5609. if (item2->GetSocket(i) >= 1 && item2->GetSocket(i) <= 2 && item2->GetSocket(i) >= item->GetValue(2))
  5610. {
  5611. // 석 확률
  5612. #ifdef ENABLE_ADDSTONE_FAILURE
  5613. if (number(1, 100) <= 100)
  5614. #else
  5615. if (1)
  5616. #endif
  5617. {
  5618. ChatInfoTrans(("메틴석 부착에 성공하였습니다."));
  5619. item2->SetSocket(i, item->GetVnum());
  5620. }
  5621. else
  5622. {
  5623. ChatInfoTrans(("메틴석 부착에 실패하였습니다."));
  5624. item2->SetSocket(i, ITEM_BROKEN_METIN_VNUM);
  5625. }
  5626.  
  5627. LogManager::instance().ItemLog(this, item2, "SOCKET", item->GetLocaleName());
  5628. ITEM_MANAGER::instance().RemoveItem(item, "REMOVE (METIN)");
  5629. break;
  5630. }
  5631.  
  5632. if (i == ITEM_SOCKET_MAX_NUM)
  5633. ChatInfoTrans(("부착할 수 있는 슬롯이 없습니다."));
  5634. }
  5635. break;
  5636.  
  5637. case ITEM_AUTOUSE:
  5638. case ITEM_MATERIAL:
  5639. case ITEM_SPECIAL:
  5640. case ITEM_TOOL:
  5641. case ITEM_LOTTERY:
  5642. break;
  5643.  
  5644. case ITEM_TOTEM:
  5645. {
  5646. if (!item->IsEquipped())
  5647. EquipItem(item);
  5648. }
  5649. break;
  5650.  
  5651. case ITEM_BLEND:
  5652. // 새로운 약초들
  5653. sys_log(0,"ITEM_BLEND!!");
  5654. if (Blend_Item_find(item->GetVnum()))
  5655. {
  5656. int affect_type = AFFECT_BLEND;
  5657. int apply_type = aApplyInfo[item->GetSocket(0)].bPointType;
  5658. int apply_value = item->GetSocket(1);
  5659. int apply_duration = item->GetSocket(2);
  5660.  
  5661. if (FindAffect(affect_type, apply_type))
  5662. {
  5663. ChatInfoTrans(("이미 효과가 걸려 있습니다."));
  5664. }
  5665. else
  5666. {
  5667. if (FindAffect(AFFECT_EXP_BONUS_EURO_FREE, POINT_RESIST_MAGIC))
  5668. {
  5669. ChatInfoTrans(("이미 효과가 걸려 있습니다."));
  5670. }
  5671. else
  5672. {
  5673. AddAffect(affect_type, apply_type, apply_value, 0, apply_duration, 0, false);
  5674. item->SetCount(item->GetCount() - 0);
  5675. }
  5676. }
  5677. }
  5678. break;
  5679. case ITEM_EXTRACT:
  5680. {
  5681. LPITEM pDestItem = GetItem(DestCell);
  5682. if (NULL == pDestItem)
  5683. {
  5684. return false;
  5685. }
  5686. switch (item->GetSubType())
  5687. {
  5688. case EXTRACT_DRAGON_SOUL:
  5689. if (pDestItem->IsDragonSoul())
  5690. {
  5691. return DSManager::instance().PullOut(this, NPOS, pDestItem, item);
  5692. }
  5693. return false;
  5694. case EXTRACT_DRAGON_HEART:
  5695. if (pDestItem->IsDragonSoul())
  5696. {
  5697. return DSManager::instance().ExtractDragonHeart(this, pDestItem, item);
  5698. }
  5699. return false;
  5700. default:
  5701. return false;
  5702. }
  5703. }
  5704. break;
  5705.  
  5706. case ITEM_GACHA:
  5707. {
  5708. DWORD dwBoxVnum = item->GetVnum();
  5709. std::vector <DWORD> dwVnums;
  5710. std::vector <DWORD> dwCounts;
  5711. std::vector <LPITEM> item_gets(0);
  5712. int count = 0;
  5713.  
  5714. if (GiveItemFromSpecialItemGroup(dwBoxVnum, dwVnums, dwCounts, item_gets, count))
  5715. {
  5716. if(item->GetSocket(0) > 1)
  5717. item->SetSocket(0, item->GetSocket(0) - 1);
  5718. else
  5719. ITEM_MANAGER::instance().RemoveItem(item, "REMOVE (ITEM_GACHA)");
  5720. }
  5721. }
  5722. break;
  5723. case ITEM_NONE:
  5724. sys_err("Item type NONE %s", item->GetLocaleName(this));
  5725. break;
  5726.  
  5727. default:
  5728. sys_log(0, "UseItemEx: Unknown type %s %d", item->GetLocaleName(this), item->GetType());
  5729. return false;
  5730. }
  5731.  
  5732. return true;
  5733. }
  5734.  
  5735. int g_nPortalLimitTime = 10;
  5736.  
  5737. bool CHARACTER::UseItem(TItemPos Cell, TItemPos DestCell)
  5738. {
  5739. WORD wCell = Cell.cell;
  5740. BYTE window_type = Cell.window_type;
  5741. //WORD wDestCell = DestCell.cell;
  5742. //BYTE bDestInven = DestCell.window_type;
  5743. LPITEM item;
  5744.  
  5745. if (!CanHandleItem())
  5746. return false;
  5747.  
  5748. if (!IsValidItemPosition(Cell) || !(item = GetItem(Cell)))
  5749. return false;
  5750.  
  5751. sys_log(0, "%s: USE_ITEM %s (inven %d, cell: %d)", GetStringName().c_str(), item->GetLocaleName(this), window_type, wCell);
  5752.  
  5753. if (item->IsExchanging())
  5754. return false;
  5755. #ifdef ENABLE_SWITCHBOT
  5756. if (Cell.IsSwitchbotPosition())
  5757. {
  5758. CSwitchbot* pkSwitchbot = CSwitchbotManager::Instance().FindSwitchbot(GetPlayerID());
  5759. if (pkSwitchbot && pkSwitchbot->IsActive(Cell.cell))
  5760. {
  5761. return false;
  5762. }
  5763.  
  5764. int iEmptyCell = GetEmptyInventory(item->GetSize());
  5765.  
  5766. if (iEmptyCell == -1)
  5767. {
  5768. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Cannot remove item from switchbot. Inventory is full."));
  5769. return false;
  5770. }
  5771.  
  5772. MoveItem(Cell, TItemPos(INVENTORY, iEmptyCell), item->GetCount());
  5773. return true;
  5774. }else
  5775. {
  5776. // if the item subtype isn't USE_CHANGE_ATTRIBUTE then check item flood.. -.-'
  5777. if(item->GetSubType() != USE_CHANGE_ATTRIBUTE)
  5778. {
  5779. if (thecore_pulse() > use_item_anti_flood_pulse() + PASSES_PER_SEC(1))
  5780. {
  5781. set_use_item_anti_flood_count(0);
  5782. set_use_item_anti_flood_pulse(thecore_pulse());
  5783. }
  5784.  
  5785. if (increase_use_item_anti_flood_count() >= 10)
  5786. {
  5787. // sys_err("Too fast result hacker: character name(%s) item name(%s) item id(%d)", GetName(), item->GetName(), item->GetVnum());
  5788. GetDesc()->DelayedDisconnect(0);
  5789. return false;
  5790. }
  5791. }
  5792. }
  5793. #endif
  5794. if (!item->CanUsedBy(this))
  5795. {
  5796. ChatInfoTrans(("군직이 맞지않아 이 아이템을 사용할 수 없습니다."));
  5797. return false;
  5798. }
  5799.  
  5800. if (IsStun())
  5801. return false;
  5802.  
  5803. if (false == FN_check_item_sex(this, item))
  5804. {
  5805. ChatInfoTrans(("성별이 맞지않아 이 아이템을 사용할 수 없습니다."));
  5806. return false;
  5807. }
  5808.  
  5809. if (IS_ENABLE_ITEM(item->GetVnum()))
  5810. {
  5811. if (false == IS_ENABLE_ITEM_ZONE(GetMapIndex()))
  5812. {
  5813. ChatInfoTrans(("Nu poti folosi acest item in aceasta mapa."));
  5814. return false;
  5815. }
  5816. }
  5817.  
  5818. //PREVENT_TRADE_WINDOW
  5819. if (IS_SUMMON_ITEM(item->GetVnum()))
  5820. {
  5821. if (CThreeWayWar::instance().IsThreeWayWarMapIndex(GetMapIndex()))
  5822. {
  5823. ChatInfoTrans(("삼거리 전투 참가중에는 귀환부,귀환기억부를 사용할수 없습니다."));
  5824. return false;
  5825. }
  5826. int iPulse = thecore_pulse();
  5827.  
  5828. if (iPulse - GetSafeboxLoadTime() < PASSES_PER_SEC(g_nPortalLimitTime))
  5829. {
  5830. ChatInfoTrans(("창고를 연후 %d초 이내에는 귀환부,귀환기억부를 사용할 수 없습니다."), g_nPortalLimitTime);
  5831.  
  5832. if (test_server)
  5833. ChatPacket(CHAT_TYPE_INFO, "[TestOnly]Pulse %d LoadTime %d PASS %d", iPulse, GetSafeboxLoadTime(), PASSES_PER_SEC(g_nPortalLimitTime));
  5834. return false;
  5835. }
  5836.  
  5837. if (GetExchange() || GetMyShop() || GetShopOwner() || IsOpenSafebox() || IsCubeOpen())
  5838. {
  5839. ChatInfoTrans(("거래창,창고 등을 연 상태에서는 귀환부,귀환기억부 를 사용할수 없습니다."));
  5840. return false;
  5841. }
  5842.  
  5843. {
  5844. if (iPulse - GetRefineTime() < PASSES_PER_SEC(g_nPortalLimitTime))
  5845. {
  5846. ChatInfoTrans(("아이템 개량후 %d초 이내에는 귀환부,귀환기억부를 사용할 수 없습니다."), g_nPortalLimitTime);
  5847. return false;
  5848. }
  5849. }
  5850.  
  5851. {
  5852. if (iPulse - GetMyShopTime() < PASSES_PER_SEC(g_nPortalLimitTime))
  5853. {
  5854. ChatInfoTrans(("개인상점 사용후 %d초 이내에는 귀환부,귀환기억부를 사용할 수 없습니다."), g_nPortalLimitTime);
  5855. return false;
  5856. }
  5857. }
  5858.  
  5859.  
  5860. if (item->GetVnum() != 70302)
  5861. {
  5862. PIXEL_POSITION posWarp;
  5863.  
  5864. int x = 0;
  5865. int y = 0;
  5866.  
  5867. double nDist = 0;
  5868. const double nDistant = 5000.0;
  5869. if (item->GetVnum() == 22010)
  5870. {
  5871. x = item->GetSocket(0) - GetX();
  5872. y = item->GetSocket(1) - GetY();
  5873. }
  5874. else if (item->GetVnum() == 22000)
  5875. {
  5876. SECTREE_MANAGER::instance().GetRecallPositionByEmpire(GetMapIndex(), GetEmpire(), posWarp);
  5877.  
  5878. if (item->GetSocket(0) == 0)
  5879. {
  5880. x = posWarp.x - GetX();
  5881. y = posWarp.y - GetY();
  5882. }
  5883. else
  5884. {
  5885. x = item->GetSocket(0) - GetX();
  5886. y = item->GetSocket(1) - GetY();
  5887. }
  5888. }
  5889.  
  5890. nDist = sqrt(pow((float)x,2) + pow((float)y,2));
  5891.  
  5892. if (nDistant > nDist)
  5893. {
  5894. ChatInfoTrans(("이동 되어질 위치와 너무 가까워 귀환부를 사용할수 없습니다."));
  5895. if (test_server)
  5896. ChatPacket(CHAT_TYPE_INFO, "PossibleDistant %f nNowDist %f", nDistant,nDist);
  5897. return false;
  5898. }
  5899. }
  5900.  
  5901. if (iPulse - GetExchangeTime() < PASSES_PER_SEC(g_nPortalLimitTime))
  5902. {
  5903. ChatInfoTrans(("거래 후 %d초 이내에는 귀환부,귀환기억부등을 사용할 수 없습니다."), g_nPortalLimitTime);
  5904. return false;
  5905. }
  5906. }
  5907.  
  5908. if ((item->GetVnum() == 50200) || (item->GetVnum() == 71049))
  5909. {
  5910. if (GetExchange() || GetMyShop() || GetShopOwner() || IsOpenSafebox() || IsCubeOpen())
  5911. {
  5912. ChatInfoTrans(("거래창,창고 등을 연 상태에서는 보따리,비단보따리를 사용할수 없습니다."));
  5913. return false;
  5914. }
  5915. }
  5916.  
  5917. if (IS_SET(item->GetFlag(), ITEM_FLAG_LOG))
  5918. {
  5919. DWORD vid = item->GetVID();
  5920. DWORD oldCount = item->GetCount();
  5921. DWORD vnum = item->GetVnum();
  5922.  
  5923. char hint[ITEM_NAME_MAX_LEN + 32 + 1];
  5924. int len = snprintf(hint, sizeof(hint) - 32, "%s", item->GetLocaleName(this));
  5925.  
  5926. if (len < 0 || len >= (int) sizeof(hint) - 32)
  5927. len = (sizeof(hint) - 32) - 1;
  5928.  
  5929. bool ret = UseItemEx(item, DestCell);
  5930.  
  5931. if (NULL == ITEM_MANAGER::instance().FindByVID(vid))
  5932. {
  5933. LogManager::instance().ItemLog(this, vid, vnum, "REMOVE", hint);
  5934. }
  5935. else if (oldCount != item->GetCount())
  5936. {
  5937. snprintf(hint + len, sizeof(hint) - len, " %u", oldCount - 1);
  5938. LogManager::instance().ItemLog(this, vid, vnum, "USE_ITEM", hint);
  5939. }
  5940. return (ret);
  5941. }
  5942. else
  5943. return UseItemEx(item, DestCell);
  5944. }
  5945.  
  5946. #ifdef ENABLE_ITEM_MAX_COUNT_1000
  5947. bool CHARACTER::DropItem(TItemPos Cell, WORD bCount)
  5948. #else
  5949. bool CHARACTER::DropItem(TItemPos Cell, BYTE bCount)
  5950. #endif
  5951. {
  5952. LPITEM item = NULL;
  5953.  
  5954. if (GetMapIndex() == OXEVENT_MAP_INDEX)
  5955. {
  5956. ChatInfoTrans(("말을 탄 상태에서 예복을 입을 수 없습니다."));
  5957. return false;
  5958. }
  5959.  
  5960. if (IsPlayer() == true && GetMapIndex() == 112 || GetMapIndex() >= 1200000 && GetMapIndex() <= 1210000)
  5961. {
  5962. ChatInfoTrans(("Nu poti arunca iteme in aceasta mapa."));
  5963. return false;
  5964. }
  5965.  
  5966. if (!CanHandleItem())
  5967. {
  5968. if (NULL != DragonSoul_RefineWindow_GetOpener())
  5969. ChatInfoTrans(("강화창을 연 상태에서는 아이템을 옮길 수 없습니다."));
  5970. return false;
  5971. }
  5972. #ifdef ENABLE_NEWSTUFF
  5973. if (0 != g_ItemDropTimeLimitValue)
  5974. {
  5975. if (get_dword_time() < m_dwLastItemDropTime+g_ItemDropTimeLimitValue)
  5976. {
  5977. ChatInfoTrans(("아직 골드를 버릴 수 없습니다."));
  5978. return false;
  5979. }
  5980. }
  5981.  
  5982. m_dwLastItemDropTime = get_dword_time();
  5983. #endif
  5984. if (IsDead())
  5985. return false;
  5986.  
  5987. if (!IsValidItemPosition(Cell) || !(item = GetItem(Cell)))
  5988. return false;
  5989.  
  5990. if (item->IsExchanging())
  5991. return false;
  5992.  
  5993. if (true == item->isLocked())
  5994. return false;
  5995.  
  5996. if (quest::CQuestManager::instance().GetPCForce(GetPlayerID())->IsRunning() == true)
  5997. return false;
  5998.  
  5999. if (IS_SET(item->GetAntiFlag(), ITEM_ANTIFLAG_DROP | ITEM_ANTIFLAG_GIVE))
  6000. {
  6001. ChatInfoTrans(("버릴 수 없는 아이템입니다."));
  6002. return false;
  6003. }
  6004.  
  6005. if (bCount == 0 || bCount > item->GetCount())
  6006. bCount = item->GetCount();
  6007.  
  6008. SyncQuickslot(QUICKSLOT_TYPE_ITEM, Cell.cell, 255); // Quickslot 에서 지움
  6009.  
  6010. LPITEM pkItemToDrop;
  6011.  
  6012. if (bCount == item->GetCount())
  6013. {
  6014. item->RemoveFromCharacter();
  6015. pkItemToDrop = item;
  6016. }
  6017. else
  6018. {
  6019. if (bCount == 0)
  6020. {
  6021. if (test_server)
  6022. sys_log(0, "[DROP_ITEM] drop item count == 0");
  6023. return false;
  6024. }
  6025.  
  6026. item->SetCount(item->GetCount() - bCount);
  6027. ITEM_MANAGER::instance().FlushDelayedSave(item);
  6028.  
  6029. pkItemToDrop = ITEM_MANAGER::instance().CreateItem(item->GetVnum(), bCount);
  6030.  
  6031. // copy item socket -- by mhh
  6032. FN_copy_item_socket(pkItemToDrop, item);
  6033.  
  6034. char szBuf[51 + 1];
  6035. snprintf(szBuf, sizeof(szBuf), "%u %u", pkItemToDrop->GetID(), pkItemToDrop->GetCount());
  6036. LogManager::instance().ItemLog(this, item, "ITEM_SPLIT", szBuf);
  6037. }
  6038.  
  6039. PIXEL_POSITION pxPos = GetXYZ();
  6040.  
  6041. if (pkItemToDrop->AddToGround(GetMapIndex(), pxPos))
  6042. {
  6043. ChatInfoTrans(("떨어진 아이템은 3분 후 사라집니다."));
  6044. #ifdef ENABLE_NEWSTUFF
  6045. pkItemToDrop->StartDestroyEvent(g_aiItemDestroyTime[ITEM_DESTROY_TIME_DROPITEM]);
  6046. #else
  6047. pkItemToDrop->StartDestroyEvent();
  6048. #endif
  6049.  
  6050. ITEM_MANAGER::instance().FlushDelayedSave(pkItemToDrop);
  6051.  
  6052. char szHint[32 + 1];
  6053. snprintf(szHint, sizeof(szHint), "%s %u %u", pkItemToDrop->GetLocaleName(this), pkItemToDrop->GetCount(), pkItemToDrop->GetOriginalVnum());
  6054. LogManager::instance().ItemLog(this, pkItemToDrop, "DROP", szHint);
  6055. //Motion(MOTION_PICKUP);
  6056. }
  6057.  
  6058. return true;
  6059. }
  6060.  
  6061. #ifdef __NEW_DROP_DIALOG__
  6062. bool CHARACTER::DestroyItem(TItemPos Cell)
  6063. {
  6064. LPITEM item = NULL;
  6065. if (!CanHandleItem())
  6066. {
  6067. if (NULL != DragonSoul_RefineWindow_GetOpener())
  6068. ChatInfoTrans(("°*E*A¢A≫ ¿¬ ≫oAA¿¡¼*´A ¾ÆAIAUA≫ ¿A±æ ¼o ¾ø½A´I´U."));
  6069. return false;
  6070. }
  6071. if (IsDead())
  6072. return false;
  6073. if (!IsValidItemPosition(Cell) || !(item = GetItem(Cell)))
  6074. return false;
  6075. if (item->IsExchanging())
  6076. return false;
  6077. if (true == item->isLocked())
  6078. return false;
  6079. if (quest::CQuestManager::instance().GetPCForce(GetPlayerID())->IsRunning() == true)
  6080. return false;
  6081. if (item->GetCount() <= 0)
  6082. return false;
  6083. SyncQuickslot(QUICKSLOT_TYPE_ITEM, Cell.cell, 255);
  6084. ITEM_MANAGER::instance().RemoveItem(item);
  6085. ChatInfoTrans(("<Sterge Item> Ai sters : |cFFc9ff00|H|h[%s]."), item->GetLocaleName(this));
  6086. return true;
  6087. }
  6088. #endif
  6089.  
  6090. bool CHARACTER::DropGold(int gold)
  6091. {
  6092. if (gold <= 0 || gold > GetGold())
  6093. return false;
  6094.  
  6095. if (!CanHandleItem())
  6096. return false;
  6097.  
  6098. if (0 != g_GoldDropTimeLimitValue)
  6099. {
  6100. if (get_dword_time() < m_dwLastGoldDropTime+g_GoldDropTimeLimitValue)
  6101. {
  6102. ChatInfoTrans(("아직 골드를 버릴 수 없습니다."));
  6103. return false;
  6104. }
  6105. }
  6106.  
  6107. m_dwLastGoldDropTime = get_dword_time();
  6108.  
  6109. LPITEM item = ITEM_MANAGER::instance().CreateItem(1, gold);
  6110.  
  6111. if (item)
  6112. {
  6113. PIXEL_POSITION pos = GetXYZ();
  6114.  
  6115. if (item->AddToGround(GetMapIndex(), pos))
  6116. {
  6117. //Motion(MOTION_PICKUP);
  6118. PointChange(POINT_GOLD, -gold, true);
  6119.  
  6120. if (gold > 1000) // 천원 이상만 기록한다.
  6121. LogManager::instance().CharLog(this, gold, "DROP_GOLD", "");
  6122.  
  6123. #ifdef ENABLE_NEWSTUFF
  6124. item->StartDestroyEvent(g_aiItemDestroyTime[ITEM_DESTROY_TIME_DROPGOLD]);
  6125. #else
  6126. item->StartDestroyEvent();
  6127. #endif
  6128. ChatInfoTrans(("떨어진 아이템은 %d분 후 사라집니다."), 150/60);
  6129. }
  6130.  
  6131. Save();
  6132. return true;
  6133. }
  6134.  
  6135. return false;
  6136. }
  6137.  
  6138. #ifdef ENABLE_ITEM_MAX_COUNT_1000
  6139. bool CHARACTER::MoveItem(TItemPos Cell, TItemPos DestCell, WORD count)
  6140. #else
  6141. bool CHARACTER::MoveItem(TItemPos Cell, TItemPos DestCell, BYTE count)
  6142. #endif
  6143. {
  6144. LPITEM item = NULL;
  6145.  
  6146. if (!IsValidItemPosition(Cell))
  6147. return false;
  6148.  
  6149. if (!(item = GetItem(Cell)))
  6150. return false;
  6151.  
  6152. if (item->IsExchanging())
  6153. return false;
  6154.  
  6155. if (item->GetCount() < count)
  6156. return false;
  6157.  
  6158. if (INVENTORY == Cell.window_type && Cell.cell >= INVENTORY_MAX_NUM && IS_SET(item->GetFlag(), ITEM_FLAG_IRREMOVABLE))
  6159. return false;
  6160.  
  6161. if (true == item->isLocked())
  6162. return false;
  6163.  
  6164. if (!IsValidItemPosition(DestCell))
  6165. {
  6166. return false;
  6167. }
  6168.  
  6169. if (!CanHandleItem())
  6170. {
  6171. if (NULL != DragonSoul_RefineWindow_GetOpener())
  6172. ChatInfoTrans(("강화창을 연 상태에서는 아이템을 옮길 수 없습니다."));
  6173. return false;
  6174. }
  6175.  
  6176. // 기획자의 요청으로 벨트 인벤토리에는 특정 타입의 아이템만 넣을 수 있다.
  6177. if (DestCell.IsBeltInventoryPosition() && false == CBeltInventoryHelper::CanMoveIntoBeltInventory(item))
  6178. {
  6179. ChatInfoTrans(("이 아이템은 벨트 인벤토리로 옮길 수 없습니다."));
  6180. return false;
  6181. }
  6182. #ifdef ENABLE_SWITCHBOT
  6183. if (Cell.IsSwitchbotPosition() && CSwitchbotManager::Instance().IsActive(GetPlayerID(), Cell.cell))
  6184. {
  6185. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Cannot move active switchbot item."));
  6186. return false;
  6187. }
  6188.  
  6189. if (DestCell.IsSwitchbotPosition() && !SwitchbotHelper::IsValidItem(item))
  6190. {
  6191. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Invalid item type for switchbot."));
  6192. return false;
  6193. }
  6194. #endif
  6195. // 이미 착용중인 아이템을 다른 곳으로 옮기는 경우, '장책 해제' 가능한 지 확인하고 옮김
  6196. if (Cell.IsEquipPosition() && !CanUnequipNow(item))
  6197. return false;
  6198.  
  6199. // if (GetWear(WEAR_WEAPON) && GetQuestFlag("timer_skill_ninja") && get_global_time() < GetQuestFlag("timer_skill_ninja"))
  6200. // {
  6201. // ChatInfoTrans(("In %d secunde poti dezechipa arma."), (GetQuestFlag("timer_skill_ninja") - get_global_time()) % 60);
  6202. // return false;
  6203. // }
  6204.  
  6205. if (DestCell.IsEquipPosition())
  6206. {
  6207. if (GetItem(DestCell)) // 장비일 경우 한 곳만 검사해도 된다.
  6208. {
  6209. ChatInfoTrans(("이미 장비를 착용하고 있습니다."));
  6210.  
  6211. return false;
  6212. }
  6213.  
  6214. EquipItem(item, DestCell.cell - INVENTORY_MAX_NUM);
  6215. }
  6216. else
  6217. {
  6218. if (item->IsDragonSoul())
  6219. {
  6220. if (item->IsEquipped())
  6221. {
  6222. return DSManager::instance().PullOut(this, DestCell, item);
  6223. }
  6224. else
  6225. {
  6226. if (DestCell.window_type != DRAGON_SOUL_INVENTORY)
  6227. {
  6228. return false;
  6229. }
  6230.  
  6231. if (!DSManager::instance().IsValidCellForThisItem(item, DestCell))
  6232. return false;
  6233. }
  6234. }
  6235. else if (DRAGON_SOUL_INVENTORY == DestCell.window_type)
  6236. return false;
  6237.  
  6238. LPITEM item2;
  6239.  
  6240. if ((item2 = GetItem(DestCell)) && item != item2 && item2->IsStackable() &&
  6241. !IS_SET(item2->GetAntiFlag(), ITEM_ANTIFLAG_STACK) &&
  6242. item2->GetVnum() == item->GetVnum()) // 합칠 수 있는 아이템의 경우
  6243. {
  6244. for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
  6245. if (item2->GetSocket(i) != item->GetSocket(i))
  6246. return false;
  6247.  
  6248. if (count == 0)
  6249. count = item->GetCount();
  6250.  
  6251. sys_log(0, "%s: ITEM_STACK %s (window: %d, cell : %d) -> (window:%d, cell %d) count %d", GetStringName().c_str(), item->GetLocaleName(this), Cell.window_type, Cell.cell,
  6252. DestCell.window_type, DestCell.cell, count);
  6253.  
  6254. #ifdef ENABLE_ITEM_MAX_COUNT_1000
  6255. count = MIN(ITEM_MAX_COUNT - item2->GetCount(), count);
  6256. #else
  6257. count = MIN(g_bItemCountLimit - item2->GetCount(), count);
  6258. #endif
  6259.  
  6260. item->SetCount(item->GetCount() - count);
  6261. item2->SetCount(item2->GetCount() + count);
  6262. return true;
  6263. }
  6264.  
  6265. if (!IsEmptyItemGrid(DestCell, item->GetSize(), Cell.cell))
  6266. return false;
  6267.  
  6268. if (count == 0 || count >= item->GetCount() || !item->IsStackable() || IS_SET(item->GetAntiFlag(), ITEM_ANTIFLAG_STACK))
  6269. {
  6270. sys_log(0, "%s: ITEM_MOVE %s (window: %d, cell : %d) -> (window:%d, cell %d) count %d", GetStringName().c_str(), item->GetLocaleName(this), Cell.window_type, Cell.cell,
  6271. DestCell.window_type, DestCell.cell, count);
  6272.  
  6273. item->RemoveFromCharacter();
  6274. SetItem(DestCell, item);
  6275.  
  6276. #ifdef ITEM_TITLE_EQUIP
  6277. if(ITEM_NORMAL_TITLE == item->GetType())
  6278. {
  6279. quest::CQuestManager::instance().UseItem(GetPlayerID(), item, false);
  6280. }
  6281. #endif
  6282.  
  6283. if (INVENTORY == Cell.window_type && INVENTORY == DestCell.window_type)
  6284. SyncQuickslot(QUICKSLOT_TYPE_ITEM, Cell.cell, DestCell.cell);
  6285. }
  6286. else if (count < item->GetCount())
  6287. {
  6288.  
  6289. sys_log(0, "%s: ITEM_SPLIT %s (window: %d, cell : %d) -> (window:%d, cell %d) count %d", GetStringName().c_str(), item->GetLocaleName(this), Cell.window_type, Cell.cell,
  6290. DestCell.window_type, DestCell.cell, count);
  6291.  
  6292. item->SetCount(item->GetCount() - count);
  6293. LPITEM item2 = ITEM_MANAGER::instance().CreateItem(item->GetVnum(), count);
  6294.  
  6295. // copy socket -- by mhh
  6296. FN_copy_item_socket(item2, item);
  6297.  
  6298. item2->AddToCharacter(this, DestCell);
  6299.  
  6300. char szBuf[51+1];
  6301. snprintf(szBuf, sizeof(szBuf), "%u %u %u %u ", item2->GetID(), item2->GetCount(), item->GetCount(), item->GetCount() + item2->GetCount());
  6302. LogManager::instance().ItemLog(this, item, "ITEM_SPLIT", szBuf);
  6303. }
  6304. }
  6305.  
  6306. return true;
  6307. }
  6308.  
  6309. namespace NPartyPickupDistribute
  6310. {
  6311. struct FFindOwnership
  6312. {
  6313. LPITEM item;
  6314. LPCHARACTER owner;
  6315.  
  6316. FFindOwnership(LPITEM item)
  6317. : item(item), owner(NULL)
  6318. {
  6319. }
  6320.  
  6321. void operator () (LPCHARACTER ch)
  6322. {
  6323. if (item->IsOwnership(ch))
  6324. owner = ch;
  6325. }
  6326. };
  6327.  
  6328. struct FCountNearMember
  6329. {
  6330. int total;
  6331. int x, y;
  6332.  
  6333. FCountNearMember(LPCHARACTER center )
  6334. : total(0), x(center->GetX()), y(center->GetY())
  6335. {
  6336. }
  6337.  
  6338. void operator () (LPCHARACTER ch)
  6339. {
  6340. if (DISTANCE_APPROX(ch->GetX() - x, ch->GetY() - y) <= PARTY_DEFAULT_RANGE)
  6341. total += 1;
  6342. }
  6343. };
  6344.  
  6345. struct FMoneyDistributor
  6346. {
  6347. int total;
  6348. LPCHARACTER c;
  6349. int x, y;
  6350. int iMoney;
  6351.  
  6352. FMoneyDistributor(LPCHARACTER center, int iMoney)
  6353. : total(0), c(center), x(center->GetX()), y(center->GetY()), iMoney(iMoney)
  6354. {
  6355. }
  6356.  
  6357. void operator ()(LPCHARACTER ch)
  6358. {
  6359. if (ch!=c)
  6360. if (DISTANCE_APPROX(ch->GetX() - x, ch->GetY() - y) <= PARTY_DEFAULT_RANGE)
  6361. {
  6362. ch->PointChange(POINT_GOLD, iMoney, true);
  6363.  
  6364. if (iMoney > 1000) // 천원 이상만 기록한다.
  6365. {
  6366. LOG_LEVEL_CHECK(LOG_LEVEL_MAX, LogManager::instance().CharLog(ch, iMoney, "GET_GOLD", ""));
  6367. }
  6368. }
  6369. }
  6370. };
  6371. }
  6372.  
  6373. void CHARACTER::GiveGold(int iAmount)
  6374. {
  6375. if (iAmount <= 0)
  6376. return;
  6377.  
  6378. sys_log(0, "GIVE_GOLD: %s %d", GetStringName().c_str(), iAmount);
  6379.  
  6380. if (GetParty())
  6381. {
  6382. LPPARTY pParty = GetParty();
  6383.  
  6384. // 파티가 있는 경우 나누어 가진다.
  6385. DWORD dwTotal = iAmount;
  6386. DWORD dwMyAmount = dwTotal;
  6387.  
  6388. NPartyPickupDistribute::FCountNearMember funcCountNearMember(this);
  6389. pParty->ForEachOnlineMember(funcCountNearMember);
  6390.  
  6391. if (funcCountNearMember.total > 1)
  6392. {
  6393. DWORD dwShare = dwTotal / funcCountNearMember.total;
  6394. dwMyAmount -= dwShare * (funcCountNearMember.total - 1);
  6395.  
  6396. NPartyPickupDistribute::FMoneyDistributor funcMoneyDist(this, dwShare);
  6397.  
  6398. pParty->ForEachOnlineMember(funcMoneyDist);
  6399. }
  6400.  
  6401. PointChange(POINT_GOLD, dwMyAmount, true);
  6402.  
  6403. if (dwMyAmount > 1000) // 천원 이상만 기록한다.
  6404. {
  6405. LOG_LEVEL_CHECK(LOG_LEVEL_MAX, LogManager::instance().CharLog(this, dwMyAmount, "GET_GOLD", ""));
  6406. }
  6407. }
  6408. else
  6409. {
  6410. PointChange(POINT_GOLD, iAmount, true);
  6411.  
  6412. if (iAmount > 1000) // 천원 이상만 기록한다.
  6413. {
  6414. LOG_LEVEL_CHECK(LOG_LEVEL_MAX, LogManager::instance().CharLog(this, iAmount, "GET_GOLD", ""));
  6415. }
  6416. }
  6417. }
  6418.  
  6419. bool CHARACTER::PickupItem(DWORD dwVID)
  6420. {
  6421. LPITEM item = ITEM_MANAGER::instance().FindByVID(dwVID);
  6422.  
  6423. if (IsObserverMode())
  6424. return false;
  6425.  
  6426. if (!item || !item->GetSectree())
  6427. return false;
  6428.  
  6429. if (item->DistanceValid(this))
  6430. {
  6431. if (item->IsOwnership(this))
  6432. {
  6433. if (item->GetType() == ITEM_ELK)
  6434. {
  6435. GiveGold(item->GetCount());
  6436. item->RemoveFromGround();
  6437.  
  6438. M2_DESTROY_ITEM(item);
  6439.  
  6440. Save();
  6441. }
  6442. else
  6443. {
  6444. if (item->IsStackable() && !IS_SET(item->GetAntiFlag(), ITEM_ANTIFLAG_STACK))
  6445. {
  6446. #ifdef ENABLE_ITEM_MAX_COUNT_1000
  6447. WORD bCount = item->GetCount();
  6448. #else
  6449. BYTE bCount = item->GetCount();
  6450. #endif
  6451.  
  6452. for (int i = 0; i < INVENTORY_MAX_NUM; ++i)
  6453. {
  6454. LPITEM item2 = GetInventoryItem(i);
  6455.  
  6456. if (!item2)
  6457. continue;
  6458.  
  6459. if (item2->GetVnum() == item->GetVnum())
  6460. {
  6461. int j;
  6462.  
  6463. for (j = 0; j < ITEM_SOCKET_MAX_NUM; ++j)
  6464. if (item2->GetSocket(j) != item->GetSocket(j))
  6465. break;
  6466.  
  6467. if (j != ITEM_SOCKET_MAX_NUM)
  6468. continue;
  6469.  
  6470. #ifdef ENABLE_ITEM_MAX_COUNT_1000
  6471. WORD bCount2 = MIN(ITEM_MAX_COUNT - item2->GetCount(), bCount);
  6472. #else
  6473. BYTE bCount2 = MIN(g_bItemCountLimit - item2->GetCount(), bCount);
  6474. #endif
  6475. bCount -= bCount2;
  6476.  
  6477.  
  6478. item2->SetCount(item2->GetCount() + bCount2);
  6479.  
  6480. if (bCount == 0)
  6481. {
  6482. ChatInfoTrans(("아이템 획득: %s"), item2->GetLocaleName(this));
  6483. M2_DESTROY_ITEM(item);
  6484. if (item2->GetType() == ITEM_QUEST)
  6485. quest::CQuestManager::instance().PickupItem (GetPlayerID(), item2);
  6486. return true;
  6487. }
  6488. }
  6489. }
  6490.  
  6491. item->SetCount(bCount);
  6492. }
  6493.  
  6494. int iEmptyCell;
  6495. if (item->IsDragonSoul())
  6496. {
  6497. if ((iEmptyCell = GetEmptyDragonSoulInventory(item)) == -1)
  6498. {
  6499. sys_log(0, "No empty ds inventory pid %u size %ud itemid %u", GetPlayerID(), item->GetSize(), item->GetID());
  6500. ChatInfoTrans(("소지하고 있는 아이템이 너무 많습니다."));
  6501. return false;
  6502. }
  6503. }
  6504. else
  6505. {
  6506. if ((iEmptyCell = GetEmptyInventory(item->GetSize())) == -1)
  6507. {
  6508. sys_log(0, "No empty inventory pid %u size %ud itemid %u", GetPlayerID(), item->GetSize(), item->GetID());
  6509. ChatInfoTrans(("소지하고 있는 아이템이 너무 많습니다."));
  6510. return false;
  6511. }
  6512. }
  6513.  
  6514. item->RemoveFromGround();
  6515.  
  6516. if (item->IsDragonSoul())
  6517. item->AddToCharacter(this, TItemPos(DRAGON_SOUL_INVENTORY, iEmptyCell));
  6518. else
  6519. item->AddToCharacter(this, TItemPos(INVENTORY, iEmptyCell));
  6520.  
  6521. char szHint[32+1];
  6522. snprintf(szHint, sizeof(szHint), "%s %u %u", item->GetLocaleName(this), item->GetCount(), item->GetOriginalVnum());
  6523. LogManager::instance().ItemLog(this, item, "GET", szHint);
  6524. ChatInfoTrans(("아이템 획득: %s"), item->GetLocaleName(this));
  6525.  
  6526. if (item->GetType() == ITEM_QUEST)
  6527. quest::CQuestManager::instance().PickupItem (GetPlayerID(), item);
  6528. }
  6529.  
  6530. //Motion(MOTION_PICKUP);
  6531. return true;
  6532. }
  6533. else if (!IS_SET(item->GetAntiFlag(), ITEM_ANTIFLAG_GIVE | ITEM_ANTIFLAG_DROP) && GetParty())
  6534. {
  6535. NPartyPickupDistribute::FFindOwnership funcFindOwnership(item);
  6536.  
  6537. GetParty()->ForEachOnlineMember(funcFindOwnership);
  6538.  
  6539. LPCHARACTER owner = funcFindOwnership.owner;
  6540. // @fixme115
  6541. if (!owner)
  6542. return false;
  6543.  
  6544. int iEmptyCell;
  6545.  
  6546. if (item->IsDragonSoul())
  6547. {
  6548. if (!(owner && (iEmptyCell = owner->GetEmptyDragonSoulInventory(item)) != -1))
  6549. {
  6550. owner = this;
  6551.  
  6552. if ((iEmptyCell = GetEmptyDragonSoulInventory(item)) == -1)
  6553. {
  6554. owner->ChatInfoTrans(("소지하고 있는 아이템이 너무 많습니다."));
  6555. return false;
  6556. }
  6557. }
  6558. }
  6559. else
  6560. {
  6561. if (!(owner && (iEmptyCell = owner->GetEmptyInventory(item->GetSize())) != -1))
  6562. {
  6563. owner = this;
  6564.  
  6565. if ((iEmptyCell = GetEmptyInventory(item->GetSize())) == -1)
  6566. {
  6567. owner->ChatInfoTrans(("소지하고 있는 아이템이 너무 많습니다."));
  6568. return false;
  6569. }
  6570. }
  6571. }
  6572.  
  6573. item->RemoveFromGround();
  6574.  
  6575. if (item->IsDragonSoul())
  6576. item->AddToCharacter(owner, TItemPos(DRAGON_SOUL_INVENTORY, iEmptyCell));
  6577. else
  6578. item->AddToCharacter(owner, TItemPos(INVENTORY, iEmptyCell));
  6579.  
  6580. char szHint[32+1];
  6581. snprintf(szHint, sizeof(szHint), "%s %u %u", item->GetLocaleName(this), item->GetCount(), item->GetOriginalVnum());
  6582. LogManager::instance().ItemLog(owner, item, "GET", szHint);
  6583.  
  6584. if (owner == this)
  6585. ChatInfoTrans(("아이템 획득: %s"), item->GetLocaleName(this));
  6586. else
  6587. {
  6588. owner->ChatInfoTrans(("아이템 획득: %s 님으로부터 %s"), GetStringName().c_str(), item->GetLocaleName(this));
  6589. ChatInfoTrans(("아이템 전달: %s 님에게 %s"), owner->GetStringName().c_str(), item->GetLocaleName(this));
  6590. }
  6591.  
  6592. if (item->GetType() == ITEM_QUEST)
  6593. quest::CQuestManager::instance().PickupItem (owner->GetPlayerID(), item);
  6594.  
  6595. return true;
  6596. }
  6597. }
  6598.  
  6599. return false;
  6600. }
  6601.  
  6602. bool CHARACTER::SwapItem(BYTE bCell, BYTE bDestCell)
  6603. {
  6604. if (!CanHandleItem())
  6605. return false;
  6606.  
  6607. TItemPos srcCell(INVENTORY, bCell), destCell(INVENTORY, bDestCell);
  6608.  
  6609. // 올바른 Cell 인지 검사
  6610. // 용혼석은 Swap할 수 없으므로, 여기서 걸림.
  6611. //if (bCell >= INVENTORY_MAX_NUM + WEAR_MAX_NUM || bDestCell >= INVENTORY_MAX_NUM + WEAR_MAX_NUM)
  6612. if (srcCell.IsDragonSoulEquipPosition() || destCell.IsDragonSoulEquipPosition())
  6613. return false;
  6614.  
  6615. // 같은 CELL 인지 검사
  6616. if (bCell == bDestCell)
  6617. return false;
  6618.  
  6619. // 둘 다 장비창 위치면 Swap 할 수 없다.
  6620. if (srcCell.IsEquipPosition() && destCell.IsEquipPosition())
  6621. return false;
  6622.  
  6623. LPITEM item1, item2;
  6624.  
  6625. // item2가 장비창에 있는 것이 되도록.
  6626. if (srcCell.IsEquipPosition())
  6627. {
  6628. item1 = GetInventoryItem(bDestCell);
  6629. item2 = GetInventoryItem(bCell);
  6630. }
  6631. else
  6632. {
  6633. item1 = GetInventoryItem(bCell);
  6634. item2 = GetInventoryItem(bDestCell);
  6635. }
  6636.  
  6637. if (!item1 || !item2)
  6638. return false;
  6639.  
  6640. if (item1 == item2)
  6641. {
  6642. sys_log(0, "[WARNING][WARNING][HACK USER!] : %s %d %d", m_stName.c_str(), bCell, bDestCell);
  6643. return false;
  6644. }
  6645.  
  6646. // item2가 bCell위치에 들어갈 수 있는지 확인한다.
  6647. if (!IsEmptyItemGrid(TItemPos (INVENTORY, item1->GetCell()), item2->GetSize(), item1->GetCell()))
  6648. return false;
  6649.  
  6650. // 바꿀 아이템이 장비창에 있으면
  6651. if (TItemPos(EQUIPMENT, item2->GetCell()).IsEquipPosition())
  6652. {
  6653. BYTE bEquipCell = item2->GetCell() - INVENTORY_MAX_NUM;
  6654. BYTE bInvenCell = item1->GetCell();
  6655.  
  6656. // 착용중인 아이템을 벗을 수 있고, 착용 예정 아이템이 착용 가능한 상태여야만 진행
  6657. if (item2->IsDragonSoul() || item2->GetType() == ITEM_BELT) // @fixme117
  6658. {
  6659. if (false == CanUnequipNow(item2) || false == CanEquipNow(item1))
  6660. return false;
  6661. }
  6662.  
  6663. if (bEquipCell != item1->FindEquipCell(this)) // 같은 위치일때만 허용
  6664. return false;
  6665.  
  6666.  
  6667. item2->RemoveFromCharacter();
  6668.  
  6669. if (item1->EquipTo(this, bEquipCell))
  6670. item2->AddToCharacter(this, TItemPos(INVENTORY, bInvenCell));
  6671. else
  6672. sys_err("SwapItem cannot equip %s! item1 %s", item2->GetLocaleName(this), item1->GetLocaleName(this));
  6673. }
  6674. else
  6675. {
  6676. BYTE bCell1 = item1->GetCell();
  6677. BYTE bCell2 = item2->GetCell();
  6678.  
  6679. item1->RemoveFromCharacter();
  6680. item2->RemoveFromCharacter();
  6681.  
  6682. item1->AddToCharacter(this, TItemPos(INVENTORY, bCell2));
  6683. item2->AddToCharacter(this, TItemPos(INVENTORY, bCell1));
  6684. }
  6685.  
  6686. return true;
  6687. }
  6688.  
  6689. bool CHARACTER::UnequipItem(LPITEM item)
  6690. {
  6691. int pos;
  6692.  
  6693. if (false == CanUnequipNow(item))
  6694. return false;
  6695.  
  6696. if (item->IsDragonSoul())
  6697. pos = GetEmptyDragonSoulInventory(item);
  6698. else
  6699. pos = GetEmptyInventory(item->GetSize());
  6700.  
  6701. // HARD CODING
  6702. if (item->GetVnum() == UNIQUE_ITEM_HIDE_ALIGNMENT_TITLE)
  6703. ShowAlignment(true);
  6704.  
  6705. #ifdef ITEM_TITLE_EQUIP
  6706. if(ITEM_NORMAL_TITLE == item->GetType())
  6707. {
  6708. quest::CQuestManager::instance().UseItem(GetPlayerID(), item, false);
  6709. }
  6710. #endif
  6711.  
  6712. item->RemoveFromCharacter();
  6713. if (item->IsDragonSoul())
  6714. {
  6715. item->AddToCharacter(this, TItemPos(DRAGON_SOUL_INVENTORY, pos));
  6716. }
  6717. else
  6718. item->AddToCharacter(this, TItemPos(INVENTORY, pos));
  6719.  
  6720. CheckMaximumPoints();
  6721.  
  6722. return true;
  6723. }
  6724.  
  6725. bool CHARACTER::EquipItem(LPITEM item, int iCandidateCell)
  6726. {
  6727. if (item->IsExchanging())
  6728. return false;
  6729.  
  6730. if (false == item->IsEquipable())
  6731. return false;
  6732.  
  6733. if (false == CanEquipNow(item))
  6734. return false;
  6735.  
  6736. int iWearCell = item->FindEquipCell(this, iCandidateCell);
  6737.  
  6738. if (iWearCell < 0)
  6739. return false;
  6740.  
  6741. if (iWearCell == WEAR_BODY && IsRiding() && (item->GetVnum() >= 11901 && item->GetVnum() <= 11904))
  6742. {
  6743. ChatInfoTrans(("말을 탄 상태에서 예복을 입을 수 없습니다."));
  6744. return false;
  6745. }
  6746.  
  6747. if (iWearCell != WEAR_ARROW && IsPolymorphed())
  6748. {
  6749. ChatInfoTrans(("둔갑 중에는 착용중인 장비를 변경할 수 없습니다."));
  6750. return false;
  6751. }
  6752.  
  6753. if (FN_check_item_sex(this, item) == false)
  6754. {
  6755. ChatInfoTrans(("성별이 맞지않아 이 아이템을 사용할 수 없습니다."));
  6756. return false;
  6757. }
  6758.  
  6759. if(item->IsRideItem() && IsRiding())
  6760. {
  6761. ChatInfoTrans(("이미 탈것을 이용중입니다."));
  6762. return false;
  6763. }
  6764.  
  6765. DWORD dwCurTime = get_dword_time();
  6766.  
  6767. if (iWearCell != WEAR_ARROW
  6768. && (dwCurTime - GetLastAttackTime() <= 1500 || dwCurTime - m_dwLastSkillTime <= 1500))
  6769. {
  6770. ChatInfoTrans(("가만히 있을 때만 착용할 수 있습니다."));
  6771. return false;
  6772. }
  6773.  
  6774. if (item->GetVnum() == 39377 && (GetMapIndex() != 61 && GetMapIndex() != 63 && GetMapIndex() != 72))
  6775. return false;
  6776.  
  6777. if (!IsGM())
  6778. {
  6779. if (thecore_pulse() > GetEquipAntiFloodPulse() + PASSES_PER_SEC(1))
  6780. {
  6781. SetEquipAntiFloodCount(0);
  6782. SetEquipAntiFloodPulse(thecore_pulse());
  6783. }
  6784.  
  6785. if (IncreaseEquipAntiFloodCount() >= 10)
  6786. {
  6787. GetDesc()->DelayedDisconnect(0);
  6788. sys_err("%s %s [anti equip spam]", __FUNCTION__, GetName());
  6789. return false;
  6790. }
  6791. }
  6792.  
  6793. //END BLOCK_DOJANG
  6794. if (IS_BLOCK_WAR_ITEMS(item->GetVnum()))
  6795. {
  6796. if (GetMapIndex() >= 1100000 && GetMapIndex() <= 1110000)
  6797. {
  6798. ChatInfoTrans(("Nu poti folosi acest item in aceasta mapa."));
  6799. return false;
  6800. }
  6801. }
  6802.  
  6803. if (iWearCell == WEAR_WEAPON)
  6804. {
  6805. if (item->GetType() == ITEM_WEAPON)
  6806. {
  6807. LPITEM costumeWeapon = GetWear(WEAR_COSTUME_WEAPON);
  6808. if (costumeWeapon && costumeWeapon->GetValue(3) != item->GetSubType() && !UnequipItem(costumeWeapon))
  6809. {
  6810. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot unequip the costume weapon. Not enough space."));
  6811. return false;
  6812. }
  6813. }
  6814. else //fishrod/pickaxe
  6815. {
  6816. LPITEM costumeWeapon = GetWear(WEAR_COSTUME_WEAPON);
  6817. if (costumeWeapon && !UnequipItem(costumeWeapon))
  6818. {
  6819. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot unequip the costume weapon. Not enough space."));
  6820. return false;
  6821. }
  6822. }
  6823. }
  6824. else if (iWearCell == WEAR_COSTUME_WEAPON)
  6825. {
  6826. if (item->GetType() == ITEM_COSTUME && item->GetSubType() == COSTUME_WEAPON)
  6827. {
  6828. LPITEM pkWeapon = GetWear(WEAR_WEAPON);
  6829. if (!pkWeapon || pkWeapon->GetType() != ITEM_WEAPON || item->GetValue(3) != pkWeapon->GetSubType())
  6830. {
  6831. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot equip the costume weapon. Wrong equipped weapon."));
  6832. return false;
  6833. }
  6834. }
  6835. }
  6836.  
  6837. if (item->IsDragonSoul())
  6838. {
  6839. if(GetInventoryItem(INVENTORY_MAX_NUM + iWearCell))
  6840. {
  6841. ChatPacket(CHAT_TYPE_INFO, "이미 같은 종류의 용혼석을 착용하고 있습니다.");
  6842. return false;
  6843. }
  6844.  
  6845. if (!item->EquipTo(this, iWearCell))
  6846. {
  6847. return false;
  6848. }
  6849. }
  6850. else
  6851. {
  6852. if (GetWear(iWearCell) && !IS_SET(GetWear(iWearCell)->GetFlag(), ITEM_FLAG_IRREMOVABLE))
  6853. {
  6854. if (item->GetWearFlag() == WEARABLE_ABILITY)
  6855. return false;
  6856.  
  6857. if (false == SwapItem(item->GetCell(), INVENTORY_MAX_NUM + iWearCell))
  6858. {
  6859. return false;
  6860. }
  6861. }
  6862. else
  6863. {
  6864. BYTE bOldCell = item->GetCell();
  6865.  
  6866. if (item->EquipTo(this, iWearCell))
  6867. {
  6868. SyncQuickslot(QUICKSLOT_TYPE_ITEM, bOldCell, iWearCell);
  6869. }
  6870. }
  6871. }
  6872.  
  6873. if (true == item->IsEquipped())
  6874. {
  6875. if (-1 != item->GetProto()->cLimitRealTimeFirstUseIndex)
  6876. {
  6877. if (0 == item->GetSocket(1))
  6878. {
  6879. long duration = (0 != item->GetSocket(0)) ? item->GetSocket(0) : item->GetProto()->aLimits[(unsigned char)(item->GetProto()->cLimitRealTimeFirstUseIndex)].lValue;
  6880.  
  6881. if (0 == duration)
  6882. duration = 60 * 60 * 24 * 7;
  6883.  
  6884. item->SetSocket(0, time(0) + duration);
  6885. item->StartRealTimeExpireEvent();
  6886. }
  6887.  
  6888. item->SetSocket(1, item->GetSocket(1) + 1);
  6889. }
  6890.  
  6891. if (item->GetVnum() == UNIQUE_ITEM_HIDE_ALIGNMENT_TITLE)
  6892. ShowAlignment(false);
  6893.  
  6894. const DWORD& dwVnum = item->GetVnum();
  6895.  
  6896. if (true == CItemVnumHelper::IsRamadanMoonRing(dwVnum))
  6897. {
  6898. this->EffectPacket(SE_EQUIP_RAMADAN_RING);
  6899. }
  6900. else if (true == CItemVnumHelper::IsHalloweenCandy(dwVnum))
  6901. {
  6902. this->EffectPacket(SE_EQUIP_HALLOWEEN_CANDY);
  6903. }
  6904. else if (true == CItemVnumHelper::IsHappinessRing(dwVnum))
  6905. {
  6906. this->EffectPacket(SE_EQUIP_HAPPINESS_RING);
  6907. }
  6908. else if (true == CItemVnumHelper::IsLovePendant(dwVnum))
  6909. {
  6910. this->EffectPacket(SE_EQUIP_LOVE_PENDANT);
  6911. }
  6912. else if (ITEM_UNIQUE == item->GetType() && 0 != item->GetSIGVnum())
  6913. {
  6914. const CSpecialItemGroup* pGroup = ITEM_MANAGER::instance().GetSpecialItemGroup(item->GetSIGVnum());
  6915. if (NULL != pGroup)
  6916. {
  6917. const CSpecialAttrGroup* pAttrGroup = ITEM_MANAGER::instance().GetSpecialAttrGroup(pGroup->GetAttrVnum(item->GetVnum()));
  6918. if (NULL != pAttrGroup)
  6919. {
  6920. const std::string& std = pAttrGroup->m_stEffectFileName;
  6921. SpecificEffectPacket(std.c_str());
  6922. }
  6923. }
  6924. }
  6925.  
  6926. if (
  6927. (ITEM_UNIQUE == item->GetType() && UNIQUE_SPECIAL_RIDE == item->GetSubType() && IS_SET(item->GetFlag(), ITEM_FLAG_QUEST_USE))
  6928. || (ITEM_UNIQUE == item->GetType() && UNIQUE_SPECIAL_MOUNT_RIDE == item->GetSubType() && IS_SET(item->GetFlag(), ITEM_FLAG_QUEST_USE))
  6929. )
  6930. {
  6931. quest::CQuestManager::instance().UseItem(GetPlayerID(), item, false);
  6932. }
  6933. #ifdef ITEM_TITLE_EQUIP
  6934. else if(ITEM_NORMAL_TITLE == item->GetType())
  6935. {
  6936. quest::CQuestManager::instance().UseItem(GetPlayerID(), item, false);
  6937. }
  6938. #endif
  6939.  
  6940. }
  6941.  
  6942. return true;
  6943. }
  6944.  
  6945. void CHARACTER::BuffOnAttr_AddBuffsFromItem(LPITEM pItem)
  6946. {
  6947. for (size_t i = 0; i < sizeof(g_aBuffOnAttrPoints)/sizeof(g_aBuffOnAttrPoints[0]); i++)
  6948. {
  6949. TMapBuffOnAttrs::iterator it = m_map_buff_on_attrs.find(g_aBuffOnAttrPoints[i]);
  6950. if (it != m_map_buff_on_attrs.end())
  6951. {
  6952. it->second->AddBuffFromItem(pItem);
  6953. }
  6954. }
  6955. }
  6956.  
  6957. void CHARACTER::BuffOnAttr_RemoveBuffsFromItem(LPITEM pItem)
  6958. {
  6959. for (size_t i = 0; i < sizeof(g_aBuffOnAttrPoints)/sizeof(g_aBuffOnAttrPoints[0]); i++)
  6960. {
  6961. TMapBuffOnAttrs::iterator it = m_map_buff_on_attrs.find(g_aBuffOnAttrPoints[i]);
  6962. if (it != m_map_buff_on_attrs.end())
  6963. {
  6964. it->second->RemoveBuffFromItem(pItem);
  6965. }
  6966. }
  6967. }
  6968.  
  6969. void CHARACTER::BuffOnAttr_ClearAll()
  6970. {
  6971. for (TMapBuffOnAttrs::iterator it = m_map_buff_on_attrs.begin(); it != m_map_buff_on_attrs.end(); it++)
  6972. {
  6973. CBuffOnAttributes* pBuff = it->second;
  6974. if (pBuff)
  6975. {
  6976. pBuff->Initialize();
  6977. }
  6978. }
  6979. }
  6980.  
  6981. void CHARACTER::BuffOnAttr_ValueChange(BYTE bType, BYTE bOldValue, BYTE bNewValue)
  6982. {
  6983. TMapBuffOnAttrs::iterator it = m_map_buff_on_attrs.find(bType);
  6984.  
  6985. if (0 == bNewValue)
  6986. {
  6987. if (m_map_buff_on_attrs.end() == it)
  6988. return;
  6989. else
  6990. it->second->Off();
  6991. }
  6992. else if(0 == bOldValue)
  6993. {
  6994. CBuffOnAttributes* pBuff = NULL;
  6995. if (m_map_buff_on_attrs.end() == it)
  6996. {
  6997. switch (bType)
  6998. {
  6999. case POINT_ENERGY:
  7000. {
  7001. static BYTE abSlot[] = { WEAR_BODY, WEAR_HEAD, WEAR_FOOTS, WEAR_WRIST, WEAR_WEAPON, WEAR_NECK, WEAR_EAR, WEAR_SHIELD };
  7002. static std::vector <BYTE> vec_slots (abSlot, abSlot + _countof(abSlot));
  7003. pBuff = M2_NEW CBuffOnAttributes(this, bType, &vec_slots);
  7004. }
  7005. break;
  7006. case POINT_COSTUME_ATTR_BONUS:
  7007. {
  7008. static BYTE abSlot[] = {WEAR_COSTUME_BODY, WEAR_COSTUME_HAIR,
  7009. #ifdef __WEAPON_COSTUME_SYSTEM__
  7010. WEAR_COSTUME_WEAPON,
  7011. #endif
  7012. };
  7013. static std::vector <BYTE> vec_slots (abSlot, abSlot + _countof(abSlot));
  7014. pBuff = M2_NEW CBuffOnAttributes(this, bType, &vec_slots);
  7015. }
  7016. break;
  7017. default:
  7018. break;
  7019. }
  7020. m_map_buff_on_attrs.insert(TMapBuffOnAttrs::value_type(bType, pBuff));
  7021.  
  7022. }
  7023. else
  7024. pBuff = it->second;
  7025. if (pBuff != NULL)
  7026. pBuff->On(bNewValue);
  7027. }
  7028. else
  7029. {
  7030. assert (m_map_buff_on_attrs.end() != it);
  7031. it->second->ChangeBuffValue(bNewValue);
  7032. }
  7033. }
  7034.  
  7035.  
  7036. LPITEM CHARACTER::FindSpecifyItem(DWORD vnum) const
  7037. {
  7038. for (int i = 0; i < INVENTORY_MAX_NUM; ++i)
  7039. if (GetInventoryItem(i) && GetInventoryItem(i)->GetVnum() == vnum)
  7040. return GetInventoryItem(i);
  7041. return NULL;
  7042. }
  7043.  
  7044. LPITEM CHARACTER::FindItemByID(DWORD id) const
  7045. {
  7046. for (int i=0 ; i < INVENTORY_MAX_NUM ; ++i)
  7047. {
  7048. if (NULL != GetInventoryItem(i) && GetInventoryItem(i)->GetID() == id)
  7049. return GetInventoryItem(i);
  7050. }
  7051.  
  7052. for (int i=BELT_INVENTORY_SLOT_START; i < BELT_INVENTORY_SLOT_END ; ++i)
  7053. {
  7054. if (NULL != GetInventoryItem(i) && GetInventoryItem(i)->GetID() == id)
  7055. return GetInventoryItem(i);
  7056. }
  7057. return NULL;
  7058. }
  7059.  
  7060. int CHARACTER::CountSpecifyItem(DWORD vnum) const
  7061. {
  7062. int count = 0;
  7063. LPITEM item;
  7064.  
  7065. for (int i = 0; i < INVENTORY_MAX_NUM; ++i)
  7066. {
  7067. item = GetInventoryItem(i);
  7068. if (NULL != item && item->GetVnum() == vnum)
  7069. {
  7070. if (m_pkMyShop && m_pkMyShop->IsSellingItem(item->GetID()))
  7071. {
  7072. continue;
  7073. }
  7074. else
  7075. {
  7076. count += item->GetCount();
  7077. }
  7078. }
  7079. }
  7080.  
  7081. return count;
  7082. }
  7083.  
  7084. void CHARACTER::RemoveSpecifyItem(DWORD vnum, DWORD count)
  7085. {
  7086. if (0 == count)
  7087. return;
  7088.  
  7089. for (UINT i = 0; i < INVENTORY_MAX_NUM; ++i)
  7090. {
  7091. if (NULL == GetInventoryItem(i))
  7092. continue;
  7093.  
  7094. if (GetInventoryItem(i)->GetVnum() != vnum)
  7095. continue;
  7096.  
  7097. if(m_pkMyShop)
  7098. {
  7099. bool isItemSelling = m_pkMyShop->IsSellingItem(GetInventoryItem(i)->GetID());
  7100. if (isItemSelling)
  7101. continue;
  7102. }
  7103.  
  7104. if (vnum >= 80003 && vnum <= 80007)
  7105. LogManager::instance().GoldBarLog(GetPlayerID(), GetInventoryItem(i)->GetID(), QUEST, "RemoveSpecifyItem");
  7106.  
  7107. if (count >= GetInventoryItem(i)->GetCount())
  7108. {
  7109. count -= GetInventoryItem(i)->GetCount();
  7110. GetInventoryItem(i)->SetCount(0);
  7111.  
  7112. if (0 == count)
  7113. return;
  7114. }
  7115. else
  7116. {
  7117. GetInventoryItem(i)->SetCount(GetInventoryItem(i)->GetCount() - count);
  7118. return;
  7119. }
  7120. }
  7121.  
  7122. if (count)
  7123. sys_log(0, "CHARACTER::RemoveSpecifyItem cannot remove enough item vnum %u, still remain %d", vnum, count);
  7124. }
  7125.  
  7126. int CHARACTER::CountSpecifyTypeItem(BYTE type) const
  7127. {
  7128. int count = 0;
  7129.  
  7130. for (int i = 0; i < INVENTORY_MAX_NUM; ++i)
  7131. {
  7132. LPITEM pItem = GetInventoryItem(i);
  7133. if (pItem != NULL && pItem->GetType() == type)
  7134. {
  7135. count += pItem->GetCount();
  7136. }
  7137. }
  7138.  
  7139. return count;
  7140. }
  7141.  
  7142. void CHARACTER::RemoveSpecifyTypeItem(BYTE type, DWORD count)
  7143. {
  7144. if (0 == count)
  7145. return;
  7146.  
  7147. for (UINT i = 0; i < INVENTORY_MAX_NUM; ++i)
  7148. {
  7149. if (NULL == GetInventoryItem(i))
  7150. continue;
  7151.  
  7152. if (GetInventoryItem(i)->GetType() != type)
  7153. continue;
  7154.  
  7155. if(m_pkMyShop)
  7156. {
  7157. bool isItemSelling = m_pkMyShop->IsSellingItem(GetInventoryItem(i)->GetID());
  7158. if (isItemSelling)
  7159. continue;
  7160. }
  7161.  
  7162. if (count >= GetInventoryItem(i)->GetCount())
  7163. {
  7164. count -= GetInventoryItem(i)->GetCount();
  7165. GetInventoryItem(i)->SetCount(0);
  7166.  
  7167. if (0 == count)
  7168. return;
  7169. }
  7170. else
  7171. {
  7172. GetInventoryItem(i)->SetCount(GetInventoryItem(i)->GetCount() - count);
  7173. return;
  7174. }
  7175. }
  7176. }
  7177.  
  7178. void CHARACTER::AutoGiveItem(LPITEM item, bool longOwnerShip)
  7179. {
  7180. if (NULL == item)
  7181. {
  7182. sys_err ("NULL point.");
  7183. return;
  7184. }
  7185. if (item->GetOwner())
  7186. {
  7187. sys_err ("item %d 's owner exists!",item->GetID());
  7188. return;
  7189. }
  7190.  
  7191. int cell;
  7192. if (item->IsDragonSoul())
  7193. {
  7194. cell = GetEmptyDragonSoulInventory(item);
  7195. }
  7196. else
  7197. {
  7198. cell = GetEmptyInventory (item->GetSize());
  7199. }
  7200.  
  7201. if (cell != -1)
  7202. {
  7203. if (item->IsDragonSoul())
  7204. item->AddToCharacter(this, TItemPos(DRAGON_SOUL_INVENTORY, cell));
  7205. else
  7206. item->AddToCharacter(this, TItemPos(INVENTORY, cell));
  7207.  
  7208. LogManager::instance().ItemLog(this, item, "SYSTEM", item->GetLocaleName(this));
  7209.  
  7210. if (item->GetType() == ITEM_USE && item->GetSubType() == USE_POTION)
  7211. {
  7212. TQuickslot * pSlot;
  7213.  
  7214. if (GetQuickslot(0, &pSlot) && pSlot->type == QUICKSLOT_TYPE_NONE)
  7215. {
  7216. TQuickslot slot;
  7217. slot.type = QUICKSLOT_TYPE_ITEM;
  7218. slot.pos = cell;
  7219. SetQuickslot(0, slot);
  7220. }
  7221. }
  7222. }
  7223. else
  7224. {
  7225. item->AddToGround (GetMapIndex(), GetXYZ());
  7226. #ifdef ENABLE_NEWSTUFF
  7227. item->StartDestroyEvent(g_aiItemDestroyTime[ITEM_DESTROY_TIME_AUTOGIVE]);
  7228. #else
  7229. item->StartDestroyEvent();
  7230. #endif
  7231.  
  7232. if (longOwnerShip)
  7233. item->SetOwnership (this, 300);
  7234. else
  7235. item->SetOwnership (this, 60);
  7236. LogManager::instance().ItemLog(this, item, "SYSTEM_DROP", item->GetLocaleName(this));
  7237. }
  7238. }
  7239.  
  7240. #ifdef ENABLE_ITEM_MAX_COUNT_1000
  7241. LPITEM CHARACTER::AutoGiveItem(DWORD dwItemVnum, WORD bCount, int iRarePct, bool bMsg)
  7242. #else
  7243. LPITEM CHARACTER::AutoGiveItem(DWORD dwItemVnum, BYTE bCount, int iRarePct, bool bMsg)
  7244. #endif
  7245. {
  7246. TItemTable * p = ITEM_MANAGER::instance().GetTable(dwItemVnum);
  7247.  
  7248. if (!p)
  7249. return NULL;
  7250.  
  7251. DBManager::instance().SendMoneyLog(MONEY_LOG_DROP, dwItemVnum, bCount);
  7252.  
  7253. if (p->dwFlags & ITEM_FLAG_STACKABLE && p->bType != ITEM_BLEND)
  7254. {
  7255. for (int i = 0; i < INVENTORY_MAX_NUM; ++i)
  7256. {
  7257. LPITEM item = GetInventoryItem(i);
  7258.  
  7259. if (!item)
  7260. continue;
  7261.  
  7262. if (item->GetVnum() == dwItemVnum && FN_check_item_socket(item))
  7263. {
  7264. if (IS_SET(p->dwFlags, ITEM_FLAG_MAKECOUNT))
  7265. {
  7266. if (bCount < p->alValues[1])
  7267. bCount = p->alValues[1];
  7268. }
  7269.  
  7270. #ifdef ENABLE_ITEM_MAX_COUNT_1000
  7271. WORD bCount2 = MIN(ITEM_MAX_COUNT - item->GetCount(), bCount);
  7272. #else
  7273. BYTE bCount2 = MIN(g_bItemCountLimit - item->GetCount(), bCount);
  7274. #endif
  7275. bCount -= bCount2;
  7276.  
  7277. item->SetCount(item->GetCount() + bCount2);
  7278.  
  7279. if (bCount == 0)
  7280. {
  7281. if (bMsg)
  7282. ChatInfoTrans(("아이템 획득: %s"), item->GetLocaleName(this));
  7283.  
  7284. return item;
  7285. }
  7286. }
  7287. }
  7288. }
  7289.  
  7290. LPITEM item = ITEM_MANAGER::instance().CreateItem(dwItemVnum, bCount, 0, true);
  7291.  
  7292. if (!item)
  7293. {
  7294. sys_err("cannot create item by vnum %u (name: %s)", dwItemVnum, GetStringName().c_str());
  7295. return NULL;
  7296. }
  7297.  
  7298. if (item->GetType() == ITEM_BLEND)
  7299. {
  7300. for (int i=0; i < INVENTORY_MAX_NUM; i++)
  7301. {
  7302. LPITEM inv_item = GetInventoryItem(i);
  7303.  
  7304. if (inv_item == NULL) continue;
  7305.  
  7306. if (inv_item->GetType() == ITEM_BLEND)
  7307. {
  7308. if (inv_item->GetVnum() == item->GetVnum())
  7309. {
  7310. if (inv_item->GetSocket(0) == item->GetSocket(0) &&
  7311. inv_item->GetSocket(1) == item->GetSocket(1) &&
  7312. inv_item->GetSocket(2) == item->GetSocket(2) &&
  7313. #ifdef ENABLE_ITEM_MAX_COUNT_1000
  7314. inv_item->GetCount() < ITEM_MAX_COUNT)
  7315. #else
  7316. inv_item->GetCount() < g_bItemCountLimit)
  7317. #endif
  7318. {
  7319. inv_item->SetCount(inv_item->GetCount() + item->GetCount());
  7320. return inv_item;
  7321. }
  7322. }
  7323. }
  7324. }
  7325. }
  7326.  
  7327. int iEmptyCell;
  7328. if (item->IsDragonSoul())
  7329. {
  7330. iEmptyCell = GetEmptyDragonSoulInventory(item);
  7331. }
  7332. else
  7333. iEmptyCell = GetEmptyInventory(item->GetSize());
  7334.  
  7335. if (iEmptyCell != -1)
  7336. {
  7337. if (bMsg)
  7338. ChatInfoTrans(("아이템 획득: %s"), item->GetLocaleName(this));
  7339.  
  7340. if (item->IsDragonSoul())
  7341. item->AddToCharacter(this, TItemPos(DRAGON_SOUL_INVENTORY, iEmptyCell));
  7342. else
  7343. item->AddToCharacter(this, TItemPos(INVENTORY, iEmptyCell));
  7344. LogManager::instance().ItemLog(this, item, "SYSTEM", item->GetLocaleName(this));
  7345.  
  7346. if (item->GetType() == ITEM_USE && item->GetSubType() == USE_POTION)
  7347. {
  7348. TQuickslot * pSlot;
  7349.  
  7350. if (GetQuickslot(0, &pSlot) && pSlot->type == QUICKSLOT_TYPE_NONE)
  7351. {
  7352. TQuickslot slot;
  7353. slot.type = QUICKSLOT_TYPE_ITEM;
  7354. slot.pos = iEmptyCell;
  7355. SetQuickslot(0, slot);
  7356. }
  7357. }
  7358. }
  7359. else
  7360. {
  7361. item->AddToGround(GetMapIndex(), GetXYZ());
  7362. #ifdef ENABLE_NEWSTUFF
  7363. item->StartDestroyEvent(g_aiItemDestroyTime[ITEM_DESTROY_TIME_AUTOGIVE]);
  7364. #else
  7365. item->StartDestroyEvent();
  7366. #endif
  7367. if (IS_SET(item->GetAntiFlag(), ITEM_ANTIFLAG_DROP))
  7368. item->SetOwnership(this, 300);
  7369. else
  7370. item->SetOwnership(this, 60);
  7371. LogManager::instance().ItemLog(this, item, "SYSTEM_DROP", item->GetLocaleName(this));
  7372. }
  7373.  
  7374. sys_log(0,
  7375. "7: %d %d", dwItemVnum, bCount);
  7376. return item;
  7377. }
  7378.  
  7379. bool CHARACTER::GiveItem(LPCHARACTER victim, TItemPos Cell)
  7380. {
  7381. if (!CanHandleItem())
  7382. return false;
  7383.  
  7384. LPITEM item = GetItem(Cell);
  7385.  
  7386. if (item && !item->IsExchanging())
  7387. {
  7388. if (victim->CanReceiveItem(this, item))
  7389. {
  7390. victim->ReceiveItem(this, item);
  7391. return true;
  7392. }
  7393. }
  7394.  
  7395. return false;
  7396. }
  7397.  
  7398. bool CHARACTER::CanReceiveItem(LPCHARACTER from, LPITEM item) const
  7399. {
  7400. if (IsPC())
  7401. return false;
  7402.  
  7403. // TOO_LONG_DISTANCE_EXCHANGE_BUG_FIX
  7404. if (DISTANCE_APPROX(GetX() - from->GetX(), GetY() - from->GetY()) > 2000)
  7405. return false;
  7406. // END_OF_TOO_LONG_DISTANCE_EXCHANGE_BUG_FIX
  7407.  
  7408. switch (GetRaceNum())
  7409. {
  7410. case fishing::CAMPFIRE_MOB:
  7411. if (item->GetType() == ITEM_FISH &&
  7412. (item->GetSubType() == FISH_ALIVE || item->GetSubType() == FISH_DEAD))
  7413. return true;
  7414. break;
  7415.  
  7416. case fishing::FISHER_MOB:
  7417. if (item->GetType() == ITEM_ROD)
  7418. return true;
  7419. break;
  7420.  
  7421. // BUILDING_NPC
  7422. case BLACKSMITH_WEAPON_MOB:
  7423. case DEVILTOWER_BLACKSMITH_WEAPON_MOB:
  7424. if (item->GetType() == ITEM_WEAPON &&
  7425. item->GetRefinedVnum())
  7426. return true;
  7427. else
  7428. return false;
  7429. break;
  7430.  
  7431. case BLACKSMITH_ARMOR_MOB:
  7432. case DEVILTOWER_BLACKSMITH_ARMOR_MOB:
  7433. if (item->GetType() == ITEM_ARMOR &&
  7434. (item->GetSubType() == ARMOR_BODY || item->GetSubType() == ARMOR_SHIELD || item->GetSubType() == ARMOR_HEAD) &&
  7435. item->GetRefinedVnum())
  7436. return true;
  7437. else
  7438. return false;
  7439. break;
  7440.  
  7441. case BLACKSMITH_ACCESSORY_MOB:
  7442. case DEVILTOWER_BLACKSMITH_ACCESSORY_MOB:
  7443. if (item->GetType() == ITEM_ARMOR &&
  7444. !(item->GetSubType() == ARMOR_BODY || item->GetSubType() == ARMOR_SHIELD || item->GetSubType() == ARMOR_HEAD) &&
  7445. item->GetRefinedVnum())
  7446. return true;
  7447. else
  7448. return false;
  7449. break;
  7450. // END_OF_BUILDING_NPC
  7451.  
  7452. case BLACKSMITH_MOB:
  7453. if (item->GetRefinedVnum() && item->GetRefineSet() < 500)
  7454. {
  7455. return true;
  7456. }
  7457. else
  7458. {
  7459. return false;
  7460. }
  7461.  
  7462. case BLACKSMITH2_MOB:
  7463. if (item->GetRefineSet() >= 500)
  7464. {
  7465. return true;
  7466. }
  7467. else
  7468. {
  7469. return false;
  7470. }
  7471.  
  7472. case ALCHEMIST_MOB:
  7473. if (item->GetRefinedVnum())
  7474. return true;
  7475. break;
  7476.  
  7477. case 20101:
  7478. case 20102:
  7479. case 20103:
  7480. // 초급 말
  7481. if (item->GetVnum() == ITEM_REVIVE_HORSE_1)
  7482. {
  7483. if (!IsDead())
  7484. {
  7485. from->ChatInfoTrans(("죽지 않은 말에게 선초를 먹일 수 없습니다."));
  7486. return false;
  7487. }
  7488. return true;
  7489. }
  7490. else if (item->GetVnum() == ITEM_HORSE_FOOD_1)
  7491. {
  7492. if (IsDead())
  7493. {
  7494. from->ChatInfoTrans(("죽은 말에게 사료를 먹일 수 없습니다."));
  7495. return false;
  7496. }
  7497. return true;
  7498. }
  7499. else if (item->GetVnum() == ITEM_HORSE_FOOD_2 || item->GetVnum() == ITEM_HORSE_FOOD_3)
  7500. {
  7501. return false;
  7502. }
  7503. break;
  7504. case 20104:
  7505. case 20105:
  7506. case 20106:
  7507. // 중급 말
  7508. if (item->GetVnum() == ITEM_REVIVE_HORSE_2)
  7509. {
  7510. if (!IsDead())
  7511. {
  7512. from->ChatInfoTrans(("죽지 않은 말에게 선초를 먹일 수 없습니다."));
  7513. return false;
  7514. }
  7515. return true;
  7516. }
  7517. else if (item->GetVnum() == ITEM_HORSE_FOOD_2)
  7518. {
  7519. if (IsDead())
  7520. {
  7521. from->ChatInfoTrans(("죽은 말에게 사료를 먹일 수 없습니다."));
  7522. return false;
  7523. }
  7524. return true;
  7525. }
  7526. else if (item->GetVnum() == ITEM_HORSE_FOOD_1 || item->GetVnum() == ITEM_HORSE_FOOD_3)
  7527. {
  7528. return false;
  7529. }
  7530. break;
  7531. case 20107:
  7532. case 20108:
  7533. case 20109:
  7534. // 고급 말
  7535. if (item->GetVnum() == ITEM_REVIVE_HORSE_3)
  7536. {
  7537. if (!IsDead())
  7538. {
  7539. from->ChatInfoTrans(("죽지 않은 말에게 선초를 먹일 수 없습니다."));
  7540. return false;
  7541. }
  7542. return true;
  7543. }
  7544. else if (item->GetVnum() == ITEM_HORSE_FOOD_3)
  7545. {
  7546. if (IsDead())
  7547. {
  7548. from->ChatInfoTrans(("죽은 말에게 사료를 먹일 수 없습니다."));
  7549. return false;
  7550. }
  7551. return true;
  7552. }
  7553. else if (item->GetVnum() == ITEM_HORSE_FOOD_1 || item->GetVnum() == ITEM_HORSE_FOOD_2)
  7554. {
  7555. return false;
  7556. }
  7557. break;
  7558. }
  7559.  
  7560. //if (IS_SET(item->GetFlag(), ITEM_FLAG_QUEST_GIVE))
  7561. {
  7562. return true;
  7563. }
  7564.  
  7565. return false;
  7566. }
  7567.  
  7568. void CHARACTER::ReceiveItem(LPCHARACTER from, LPITEM item)
  7569. {
  7570. if (IsPC())
  7571. return;
  7572.  
  7573. switch (GetRaceNum())
  7574. {
  7575. case fishing::CAMPFIRE_MOB:
  7576. if (item->GetType() == ITEM_FISH && (item->GetSubType() == FISH_ALIVE || item->GetSubType() == FISH_DEAD))
  7577. fishing::Grill(from, item);
  7578. else
  7579. {
  7580. // TAKE_ITEM_BUG_FIX
  7581. from->SetQuestNPCID(GetVID());
  7582. // END_OF_TAKE_ITEM_BUG_FIX
  7583. quest::CQuestManager::instance().TakeItem(from->GetPlayerID(), GetRaceNum(), item);
  7584. }
  7585. break;
  7586.  
  7587. // DEVILTOWER_NPC
  7588. case DEVILTOWER_BLACKSMITH_WEAPON_MOB:
  7589. case DEVILTOWER_BLACKSMITH_ARMOR_MOB:
  7590. case DEVILTOWER_BLACKSMITH_ACCESSORY_MOB:
  7591. if (item->GetRefinedVnum() != 0 && item->GetRefineSet() != 0 && item->GetRefineSet() < 500)
  7592. {
  7593. from->SetRefineNPC(this);
  7594. from->RefineInformation(item->GetCell(), REFINE_TYPE_MONEY_ONLY);
  7595. }
  7596. else
  7597. {
  7598. from->ChatInfoTrans(("이 아이템은 개량할 수 없습니다."));
  7599. }
  7600. break;
  7601. // END_OF_DEVILTOWER_NPC
  7602.  
  7603. case BLACKSMITH_MOB:
  7604. case BLACKSMITH2_MOB:
  7605. case BLACKSMITH_WEAPON_MOB:
  7606. case BLACKSMITH_ARMOR_MOB:
  7607. case BLACKSMITH_ACCESSORY_MOB:
  7608. if (item->GetRefinedVnum())
  7609. {
  7610. from->SetRefineNPC(this);
  7611. from->RefineInformation(item->GetCell(), REFINE_TYPE_NORMAL);
  7612. }
  7613. else
  7614. {
  7615. from->ChatInfoTrans(("이 아이템은 개량할 수 없습니다."));
  7616. }
  7617. break;
  7618.  
  7619. case 20101:
  7620. case 20102:
  7621. case 20103:
  7622. case 20104:
  7623. case 20105:
  7624. case 20106:
  7625. case 20107:
  7626. case 20108:
  7627. case 20109:
  7628. if (item->GetVnum() == ITEM_REVIVE_HORSE_1 ||
  7629. item->GetVnum() == ITEM_REVIVE_HORSE_2 ||
  7630. item->GetVnum() == ITEM_REVIVE_HORSE_3)
  7631. {
  7632. from->ReviveHorse();
  7633. item->SetCount(item->GetCount()-1);
  7634. from->ChatInfoTrans(("말에게 선초를 주었습니다."));
  7635. }
  7636. else if (item->GetVnum() == ITEM_HORSE_FOOD_1 ||
  7637. item->GetVnum() == ITEM_HORSE_FOOD_2 ||
  7638. item->GetVnum() == ITEM_HORSE_FOOD_3)
  7639. {
  7640. from->FeedHorse();
  7641. from->ChatInfoTrans(("말에게 사료를 주었습니다."));
  7642. item->SetCount(item->GetCount()-1);
  7643. EffectPacket(SE_HPUP_RED);
  7644. }
  7645. break;
  7646.  
  7647. default:
  7648. sys_log(0, "TakeItem %s %d %s", from->GetStringName().c_str(), GetRaceNum(), item->GetLocaleName(this));
  7649. from->SetQuestNPCID(GetVID());
  7650. quest::CQuestManager::instance().TakeItem(from->GetPlayerID(), GetRaceNum(), item);
  7651. break;
  7652. }
  7653. }
  7654.  
  7655. bool CHARACTER::IsEquipUniqueItem(DWORD dwItemVnum) const
  7656. {
  7657. {
  7658. LPITEM u = GetWear(WEAR_UNIQUE1);
  7659.  
  7660. if (u && u->GetVnum() == dwItemVnum)
  7661. return true;
  7662. }
  7663.  
  7664. {
  7665. LPITEM u = GetWear(WEAR_UNIQUE2);
  7666.  
  7667. if (u && u->GetVnum() == dwItemVnum)
  7668. return true;
  7669. }
  7670.  
  7671. // 언어반지인 경우 언어반지(견본) 인지도 체크한다.
  7672. if (dwItemVnum == UNIQUE_ITEM_RING_OF_LANGUAGE)
  7673. return IsEquipUniqueItem(UNIQUE_ITEM_RING_OF_LANGUAGE_SAMPLE);
  7674.  
  7675. return false;
  7676. }
  7677.  
  7678. // CHECK_UNIQUE_GROUP
  7679. bool CHARACTER::IsEquipUniqueGroup(DWORD dwGroupVnum) const
  7680. {
  7681. {
  7682. LPITEM u = GetWear(WEAR_UNIQUE1);
  7683.  
  7684. if (u && u->GetSpecialGroup() == (int) dwGroupVnum)
  7685. return true;
  7686. }
  7687.  
  7688. {
  7689. LPITEM u = GetWear(WEAR_UNIQUE2);
  7690.  
  7691. if (u && u->GetSpecialGroup() == (int) dwGroupVnum)
  7692. return true;
  7693. }
  7694.  
  7695. return false;
  7696. }
  7697. // END_OF_CHECK_UNIQUE_GROUP
  7698.  
  7699. void CHARACTER::SetRefineMode(int iAdditionalCell)
  7700. {
  7701. m_iRefineAdditionalCell = iAdditionalCell;
  7702. m_bUnderRefine = true;
  7703. }
  7704.  
  7705. void CHARACTER::ClearRefineMode()
  7706. {
  7707. m_bUnderRefine = false;
  7708. SetRefineNPC( NULL );
  7709. }
  7710.  
  7711. bool CHARACTER::GiveItemFromSpecialItemGroup(DWORD dwGroupNum, std::vector<DWORD> &dwItemVnums,
  7712. std::vector<DWORD> &dwItemCounts, std::vector <LPITEM> &item_gets, int &count)
  7713. {
  7714. const CSpecialItemGroup* pGroup = ITEM_MANAGER::instance().GetSpecialItemGroup(dwGroupNum);
  7715.  
  7716. if (!pGroup)
  7717. {
  7718. sys_err("cannot find special item group %d", dwGroupNum);
  7719. return false;
  7720. }
  7721.  
  7722. std::vector <int> idxes;
  7723. int n = pGroup->GetMultiIndex(idxes);
  7724.  
  7725. bool bSuccess;
  7726.  
  7727. for (int i = 0; i < n; i++)
  7728. {
  7729. bSuccess = false;
  7730. int idx = idxes[i];
  7731. DWORD dwVnum = pGroup->GetVnum(idx);
  7732. DWORD dwCount = pGroup->GetCount(idx);
  7733. int iRarePct = pGroup->GetRarePct(idx);
  7734. LPITEM item_get = NULL;
  7735. switch (dwVnum)
  7736. {
  7737. case CSpecialItemGroup::GOLD:
  7738. PointChange(POINT_GOLD, dwCount);
  7739. LogManager::instance().CharLog(this, dwCount, "TREASURE_GOLD", "");
  7740.  
  7741. bSuccess = true;
  7742. break;
  7743. case CSpecialItemGroup::EXP:
  7744. {
  7745. PointChange(POINT_EXP, dwCount);
  7746. LogManager::instance().CharLog(this, dwCount, "TREASURE_EXP", "");
  7747.  
  7748. bSuccess = true;
  7749. }
  7750. break;
  7751.  
  7752. case CSpecialItemGroup::MOB:
  7753. {
  7754. sys_log(0, "CSpecialItemGroup::MOB %d", dwCount);
  7755. int x = GetX() + number(-500, 500);
  7756. int y = GetY() + number(-500, 500);
  7757.  
  7758. LPCHARACTER ch = CHARACTER_MANAGER::instance().SpawnMob(dwCount, GetMapIndex(), x, y, 0, true, -1);
  7759. if (ch)
  7760. ch->SetAggressive();
  7761. bSuccess = true;
  7762. }
  7763. break;
  7764. case CSpecialItemGroup::SLOW:
  7765. {
  7766. sys_log(0, "CSpecialItemGroup::SLOW %d", -(int)dwCount);
  7767. AddAffect(AFFECT_SLOW, POINT_MOV_SPEED, -(int)dwCount, AFF_SLOW, 300, 0, true);
  7768. bSuccess = true;
  7769. }
  7770. break;
  7771. case CSpecialItemGroup::DRAIN_HP:
  7772. {
  7773. int iDropHP = GetMaxHP()*dwCount/100;
  7774. sys_log(0, "CSpecialItemGroup::DRAIN_HP %d", -iDropHP);
  7775. iDropHP = MIN(iDropHP, GetHP()-1);
  7776. sys_log(0, "CSpecialItemGroup::DRAIN_HP %d", -iDropHP);
  7777. PointChange(POINT_HP, -iDropHP);
  7778. bSuccess = true;
  7779. }
  7780. break;
  7781. case CSpecialItemGroup::POISON:
  7782. {
  7783. AttackedByPoison(NULL);
  7784. bSuccess = true;
  7785. }
  7786. break;
  7787. #ifdef ENABLE_WOLFMAN_CHARACTER
  7788. case CSpecialItemGroup::BLEEDING:
  7789. {
  7790. AttackedByBleeding(NULL);
  7791. bSuccess = true;
  7792. }
  7793. break;
  7794. #endif
  7795. case CSpecialItemGroup::MOB_GROUP:
  7796. {
  7797. int sx = GetX() - number(300, 500);
  7798. int sy = GetY() - number(300, 500);
  7799. int ex = GetX() + number(300, 500);
  7800. int ey = GetY() + number(300, 500);
  7801. CHARACTER_MANAGER::instance().SpawnGroup(dwCount, GetMapIndex(), sx, sy, ex, ey, NULL, true);
  7802.  
  7803. bSuccess = true;
  7804. }
  7805. break;
  7806. default:
  7807. {
  7808. item_get = AutoGiveItem(dwVnum, dwCount, iRarePct);
  7809.  
  7810. if (item_get)
  7811. {
  7812. bSuccess = true;
  7813. }
  7814. }
  7815. break;
  7816. }
  7817.  
  7818. if (bSuccess)
  7819. {
  7820. dwItemVnums.push_back(dwVnum);
  7821. dwItemCounts.push_back(dwCount);
  7822. item_gets.push_back(item_get);
  7823. count++;
  7824.  
  7825. }
  7826. else
  7827. {
  7828. return false;
  7829. }
  7830. }
  7831. return bSuccess;
  7832. }
  7833.  
  7834. // NEW_HAIR_STYLE_ADD
  7835. bool CHARACTER::ItemProcess_Hair(LPITEM item, int iDestCell)
  7836. {
  7837. if (item->CheckItemUseLevel(GetLevel()) == false)
  7838. {
  7839. // 레벨 제한에 걸림
  7840. ChatInfoTrans(("아직 이 머리를 사용할 수 없는 레벨입니다."));
  7841. return false;
  7842. }
  7843.  
  7844. DWORD hair = item->GetVnum();
  7845.  
  7846. switch (GetJob())
  7847. {
  7848. case JOB_WARRIOR :
  7849. hair -= 72000; // 73001 - 72000 = 1001 부터 헤어 번호 시작
  7850. break;
  7851.  
  7852. case JOB_ASSASSIN :
  7853. hair -= 71250;
  7854. break;
  7855.  
  7856. case JOB_SURA :
  7857. hair -= 70500;
  7858. break;
  7859.  
  7860. case JOB_SHAMAN :
  7861. hair -= 69750;
  7862. break;
  7863. #ifdef ENABLE_WOLFMAN_CHARACTER
  7864. case JOB_WOLFMAN:
  7865. break; // NOTE: 이 헤어코드는 안 쓰이므로 패스. (현재 헤어시스템은 이미 코스튬으로 대체 된 상태임)
  7866. #endif
  7867. default :
  7868. return false;
  7869. break;
  7870. }
  7871.  
  7872. if (hair == GetPart(PART_HAIR))
  7873. {
  7874. ChatInfoTrans(("동일한 머리 스타일로는 교체할 수 없습니다."));
  7875. return true;
  7876. }
  7877.  
  7878. item->SetCount(item->GetCount() - 0);
  7879.  
  7880. SetPart(PART_HAIR, hair);
  7881. UpdatePacket();
  7882.  
  7883. return true;
  7884. }
  7885. // END_NEW_HAIR_STYLE_ADD
  7886.  
  7887. bool CHARACTER::ItemProcess_Polymorph(LPITEM item)
  7888. {
  7889. if (IsPolymorphed())
  7890. {
  7891. ChatInfoTrans(("이미 둔갑중인 상태입니다."));
  7892. return false;
  7893. }
  7894.  
  7895. if (true == IsRiding())
  7896. {
  7897. ChatInfoTrans(("둔갑할 수 없는 상태입니다."));
  7898. return false;
  7899. }
  7900.  
  7901. DWORD dwVnum = item->GetSocket(0);
  7902.  
  7903. if (dwVnum == 0)
  7904. {
  7905. ChatInfoTrans(("잘못된 둔갑 아이템입니다."));
  7906. item->SetCount(item->GetCount()-1);
  7907. return false;
  7908. }
  7909.  
  7910. const CMob* pMob = CMobManager::instance().Get(dwVnum);
  7911.  
  7912. if (pMob == NULL)
  7913. {
  7914. ChatInfoTrans(("잘못된 둔갑 아이템입니다."));
  7915. item->SetCount(item->GetCount()-1);
  7916. return false;
  7917. }
  7918.  
  7919. switch (item->GetVnum())
  7920. {
  7921. case 70104 :
  7922. case 70105 :
  7923. case 70106 :
  7924. case 70107 :
  7925. case 71093 :
  7926. {
  7927. // 둔갑구 처리
  7928. sys_log(0, "USE_POLYMORPH_BALL PID(%d) vnum(%d)", GetPlayerID(), dwVnum);
  7929.  
  7930. // 레벨 제한 체크
  7931. int iPolymorphLevelLimit = MAX(0, 20 - GetLevel() * 3 / 10);
  7932. if (pMob->m_table.bLevel >= GetLevel() + iPolymorphLevelLimit)
  7933. {
  7934. ChatInfoTrans(("나보다 너무 높은 레벨의 몬스터로는 변신 할 수 없습니다."));
  7935. return false;
  7936. }
  7937.  
  7938. int iDuration = GetSkillLevel(POLYMORPH_SKILL_ID) == 0 ? 5 : (5 + (5 + GetSkillLevel(POLYMORPH_SKILL_ID)/40 * 25));
  7939. iDuration *= 60;
  7940.  
  7941. DWORD dwBonus = 0;
  7942.  
  7943. dwBonus = (2 + GetSkillLevel(POLYMORPH_SKILL_ID)/40) * 100;
  7944.  
  7945. AddAffect(AFFECT_POLYMORPH, POINT_POLYMORPH, dwVnum, AFF_POLYMORPH, iDuration, 0, true);
  7946. AddAffect(AFFECT_POLYMORPH, POINT_ATT_BONUS, dwBonus, AFF_POLYMORPH, iDuration, 0, false);
  7947.  
  7948. item->SetCount(item->GetCount()-1);
  7949. }
  7950. break;
  7951.  
  7952. case 50322:
  7953. {
  7954. // 보류
  7955.  
  7956. // 둔갑서 처리
  7957. // 소켓0 소켓1 소켓2
  7958. // 둔갑할 몬스터 번호 수련정도 둔갑서 레벨
  7959. sys_log(0, "USE_POLYMORPH_BOOK: %s(%u) vnum(%u)", GetStringName().c_str(), GetPlayerID(), dwVnum);
  7960.  
  7961. if (CPolymorphUtils::instance().PolymorphCharacter(this, item, pMob) == true)
  7962. {
  7963. CPolymorphUtils::instance().UpdateBookPracticeGrade(this, item);
  7964. }
  7965. else
  7966. {
  7967. }
  7968. }
  7969. break;
  7970.  
  7971. default :
  7972. sys_err("POLYMORPH invalid item passed PID(%d) vnum(%d)", GetPlayerID(), item->GetOriginalVnum());
  7973. return false;
  7974. }
  7975.  
  7976. return true;
  7977. }
  7978.  
  7979. bool CHARACTER::CanDoCube() const
  7980. {
  7981. if (m_bIsObserver) return false;
  7982. if (GetShop()) return false;
  7983. if (GetMyShop()) return false;
  7984. if (m_bUnderRefine) return false;
  7985. if (IsWarping()) return false;
  7986.  
  7987. return true;
  7988. }
  7989.  
  7990. bool CHARACTER::UnEquipSpecialRideUniqueItem()
  7991. {
  7992. LPITEM Unique1 = GetWear(WEAR_UNIQUE1);
  7993. LPITEM Unique2 = GetWear(WEAR_UNIQUE2);
  7994.  
  7995. if( NULL != Unique1 )
  7996. {
  7997. if( UNIQUE_GROUP_SPECIAL_RIDE == Unique1->GetSpecialGroup() )
  7998. {
  7999. return UnequipItem(Unique1);
  8000. }
  8001. }
  8002.  
  8003. if( NULL != Unique2 )
  8004. {
  8005. if( UNIQUE_GROUP_SPECIAL_RIDE == Unique2->GetSpecialGroup() )
  8006. {
  8007. return UnequipItem(Unique2);
  8008. }
  8009. }
  8010.  
  8011.  
  8012. return true;
  8013. }
  8014.  
  8015. void CHARACTER::AutoRecoveryItemProcess(const EAffectTypes type)
  8016. {
  8017. if (true == IsDead() || true == IsStun())
  8018. return;
  8019.  
  8020. if (false == IsPC())
  8021. return;
  8022.  
  8023. if (AFFECT_AUTO_HP_RECOVERY != type && AFFECT_AUTO_SP_RECOVERY != type)
  8024. return;
  8025.  
  8026. if (NULL != FindAffect(AFFECT_STUN))
  8027. return;
  8028.  
  8029. {
  8030. const DWORD stunSkills[] = { SKILL_TANHWAN, SKILL_GEOMPUNG, SKILL_BYEURAK, SKILL_GIGUNG };
  8031.  
  8032. for (size_t i=0 ; i < sizeof(stunSkills)/sizeof(DWORD) ; ++i)
  8033. {
  8034. const CAffect* p = FindAffect(stunSkills[i]);
  8035.  
  8036. if (NULL != p && AFF_STUN == p->dwFlag)
  8037. return;
  8038. }
  8039. }
  8040.  
  8041. const CAffect* pAffect = FindAffect(type);
  8042. const size_t idx_of_amount_of_used = 1;
  8043. const size_t idx_of_amount_of_full = 2;
  8044.  
  8045. if (NULL != pAffect)
  8046. {
  8047. LPITEM pItem = FindItemByID(pAffect->dwFlag);
  8048.  
  8049. if (NULL != pItem && true == pItem->GetSocket(0))
  8050. {
  8051. if (false == CArenaManager::instance().IsArenaMap(GetMapIndex()))
  8052. {
  8053. const long amount_of_used = pItem->GetSocket(idx_of_amount_of_used);
  8054. const long amount_of_full = pItem->GetSocket(idx_of_amount_of_full);
  8055.  
  8056. const int32_t avail = amount_of_full - amount_of_used;
  8057.  
  8058. int32_t amount = 0;
  8059.  
  8060. if (AFFECT_AUTO_HP_RECOVERY == type)
  8061. {
  8062. amount = GetMaxHP() - (GetHP() + GetPoint(POINT_HP_RECOVERY));
  8063. }
  8064. else if (AFFECT_AUTO_SP_RECOVERY == type)
  8065. {
  8066. amount = GetMaxSP() - (GetSP() + GetPoint(POINT_SP_RECOVERY));
  8067. }
  8068.  
  8069. if (amount > 0)
  8070. {
  8071. if (avail > amount)
  8072. {
  8073. const int pct_of_used = amount_of_used * 100 / amount_of_full;
  8074. const int pct_of_will_used = (amount_of_used + amount) * 100 / amount_of_full;
  8075.  
  8076. bool bLog = false;
  8077. // 사용량의 10% 단위로 로그를 남김
  8078. // (사용량의 %에서, 십의 자리가 바뀔 때마다 로그를 남김.)
  8079. if ((pct_of_will_used / 10) - (pct_of_used / 10) >= 1)
  8080. bLog = true;
  8081. pItem->SetSocket(idx_of_amount_of_used, amount_of_used + amount, bLog);
  8082. }
  8083. else
  8084. {
  8085. amount = avail;
  8086.  
  8087. ITEM_MANAGER::instance().RemoveItem( pItem );
  8088. }
  8089.  
  8090. if (AFFECT_AUTO_HP_RECOVERY == type)
  8091. {
  8092. PointChange( POINT_HP_RECOVERY, amount );
  8093. EffectPacket( SE_AUTO_HPUP );
  8094. }
  8095. else if (AFFECT_AUTO_SP_RECOVERY == type)
  8096. {
  8097. PointChange( POINT_SP_RECOVERY, amount );
  8098. EffectPacket( SE_AUTO_SPUP );
  8099. }
  8100. }
  8101. }
  8102. else
  8103. {
  8104. pItem->Lock(false);
  8105. pItem->SetSocket(0, false);
  8106. RemoveAffect( const_cast<CAffect*>(pAffect) );
  8107. }
  8108. }
  8109. else
  8110. {
  8111. RemoveAffect( const_cast<CAffect*>(pAffect) );
  8112. }
  8113. }
  8114. }
  8115.  
  8116. bool CHARACTER::IsValidItemPosition(TItemPos Pos) const
  8117. {
  8118. BYTE window_type = Pos.window_type;
  8119. WORD cell = Pos.cell;
  8120.  
  8121. switch (window_type)
  8122. {
  8123. case RESERVED_WINDOW:
  8124. return false;
  8125.  
  8126. case INVENTORY:
  8127. case EQUIPMENT:
  8128. return cell < (INVENTORY_AND_EQUIP_SLOT_MAX);
  8129.  
  8130. case DRAGON_SOUL_INVENTORY:
  8131. return cell < (DRAGON_SOUL_INVENTORY_MAX_NUM);
  8132.  
  8133. case SAFEBOX:
  8134. if (NULL != m_pkSafebox)
  8135. return m_pkSafebox->IsValidPosition(cell);
  8136. else
  8137. return false;
  8138.  
  8139. case MALL:
  8140. if (NULL != m_pkMall)
  8141. return m_pkMall->IsValidPosition(cell);
  8142. else
  8143. return false;
  8144. #ifdef ENABLE_SWITCHBOT
  8145. case SWITCHBOT:
  8146. return cell < SWITCHBOT_SLOT_COUNT;
  8147. #endif
  8148.  
  8149. default:
  8150. return false;
  8151. }
  8152. }
  8153.  
  8154. #define VERIFY_MSG(exp, msg) \
  8155. if (true == (exp)) { \
  8156. ChatInfoTrans((msg)); \
  8157. return false; \
  8158. }
  8159.  
  8160. bool CHARACTER::CanEquipNow(const LPITEM item, const TItemPos& srcCell, const TItemPos& destCell) /*const*/
  8161. {
  8162. const TItemTable* itemTable = item->GetProto();
  8163. switch (GetJob())
  8164. {
  8165. case JOB_WARRIOR:
  8166. if (item->GetAntiFlag() & ITEM_ANTIFLAG_WARRIOR)
  8167. return false;
  8168. break;
  8169.  
  8170. case JOB_ASSASSIN:
  8171. if (item->GetAntiFlag() & ITEM_ANTIFLAG_ASSASSIN)
  8172. return false;
  8173. break;
  8174.  
  8175. case JOB_SHAMAN:
  8176. if (item->GetAntiFlag() & ITEM_ANTIFLAG_SHAMAN)
  8177. return false;
  8178. break;
  8179.  
  8180. case JOB_SURA:
  8181. if (item->GetAntiFlag() & ITEM_ANTIFLAG_SURA)
  8182. return false;
  8183. break;
  8184. #ifdef ENABLE_WOLFMAN_CHARACTER
  8185. case JOB_WOLFMAN:
  8186. if (item->GetAntiFlag() & ITEM_ANTIFLAG_WOLFMAN)
  8187. return false;
  8188. break;
  8189. #endif
  8190. }
  8191.  
  8192. for (int i = 0; i < ITEM_LIMIT_MAX_NUM; ++i)
  8193. {
  8194. long limit = itemTable->aLimits[i].lValue;
  8195. switch (itemTable->aLimits[i].bType)
  8196. {
  8197. case LIMIT_LEVEL:
  8198. if (GetLevel() < limit)
  8199. {
  8200. ChatInfoTrans(("레벨이 낮아 착용할 수 없습니다."));
  8201. return false;
  8202. }
  8203. break;
  8204.  
  8205. case LIMIT_CHAMPION:
  8206. if (GetConquerorLevel() < limit)
  8207. {
  8208. ChatInfoTrans(("아이템의 레벨 제한보다 레벨이 낮습니다."));
  8209. return false;
  8210. }
  8211. break;
  8212.  
  8213. case LIMIT_STR:
  8214. if (GetPoint(POINT_ST) < limit)
  8215. {
  8216. ChatInfoTrans(("근력이 낮아 착용할 수 없습니다."));
  8217. return false;
  8218. }
  8219. break;
  8220.  
  8221. case LIMIT_INT:
  8222. if (GetPoint(POINT_IQ) < limit)
  8223. {
  8224. ChatInfoTrans(("지능이 낮아 착용할 수 없습니다."));
  8225. return false;
  8226. }
  8227. break;
  8228.  
  8229. case LIMIT_DEX:
  8230. if (GetPoint(POINT_DX) < limit)
  8231. {
  8232. ChatInfoTrans(("민첩이 낮아 착용할 수 없습니다."));
  8233. return false;
  8234. }
  8235. break;
  8236.  
  8237. case LIMIT_CON:
  8238. if (GetPoint(POINT_HT) < limit)
  8239. {
  8240. ChatInfoTrans(("체력이 낮아 착용할 수 없습니다."));
  8241. return false;
  8242. }
  8243. break;
  8244. }
  8245. }
  8246.  
  8247. if (item->GetWearFlag() & WEARABLE_UNIQUE)
  8248. {
  8249. if ((GetWear(WEAR_UNIQUE1) && GetWear(WEAR_UNIQUE1)->IsSameSpecialGroup(item)) ||
  8250. (GetWear(WEAR_UNIQUE2) && GetWear(WEAR_UNIQUE2)->IsSameSpecialGroup(item)))
  8251. {
  8252. ChatInfoTrans(("같은 종류의 유니크 아이템 두 개를 동시에 장착할 수 없습니다."));
  8253. return false;
  8254. }
  8255.  
  8256. if (marriage::CManager::instance().IsMarriageUniqueItem(item->GetVnum()) &&
  8257. !marriage::CManager::instance().IsMarried(GetPlayerID()))
  8258. {
  8259. ChatInfoTrans(("결혼하지 않은 상태에서 예물을 착용할 수 없습니다."));
  8260. return false;
  8261. }
  8262. }
  8263.  
  8264. #ifdef __EFFECT_SYSTEM__
  8265. if (item->GetType() == ITEM_WEAPON && item->GetSubType() != WEAPON_ARROW)
  8266. {
  8267. LPITEM pkItem = GetWear(WEAR_EFFECT_WEAPON);
  8268. if (pkItem)
  8269. {
  8270. ChatInfoTrans(("You must unwear the weapon effect before."));
  8271. return false;
  8272. }
  8273. }
  8274. else if (item->GetType() == ITEM_ARMOR && item->GetSubType() == ARMOR_BODY)
  8275. {
  8276. LPITEM pkItem = GetWear(WEAR_EFFECT_ARMOR);
  8277. if (pkItem)
  8278. {
  8279. ChatInfoTrans(("You must unwear the armor effect before."));
  8280. return false;
  8281. }
  8282. }
  8283. else if (item->GetType() == ITEM_COSTUME && item->GetSubType() == USE_EFFECT)
  8284. {
  8285. if (item->GetWearFlag() & WEARABLE_EFFECT_ARMOR)
  8286. {
  8287. LPITEM pkItem = GetWear(WEAR_BODY);
  8288. if (!pkItem)
  8289. {
  8290. ChatInfoTrans(("To can wear a armor effect you must have a armor weared."));
  8291. return false;
  8292. }
  8293. }
  8294. else
  8295. {
  8296. LPITEM pkItem = GetWear(WEAR_WEAPON);
  8297. if (!pkItem)
  8298. {
  8299. ChatInfoTrans(("To can wear a weapon effect you must have a weapon weared."));
  8300. return false;
  8301. }
  8302. }
  8303. }
  8304. #endif
  8305.  
  8306.  
  8307. return true;
  8308. }
  8309.  
  8310. bool CHARACTER::CanUnequipNow(const LPITEM item, const TItemPos& srcCell, const TItemPos& destCell) /*const*/
  8311. {
  8312.  
  8313. if (ITEM_BELT == item->GetType())
  8314. VERIFY_MSG(CBeltInventoryHelper::IsExistItemInBeltInventory(this), "벨트 인벤토리에 아이템이 존재하면 해제할 수 없습니다.");
  8315.  
  8316. if (IS_SET(item->GetFlag(), ITEM_FLAG_IRREMOVABLE))
  8317. return false;
  8318.  
  8319. {
  8320. int pos = -1;
  8321.  
  8322. if (item->IsDragonSoul())
  8323. pos = GetEmptyDragonSoulInventory(item);
  8324. else
  8325. pos = GetEmptyInventory(item->GetSize());
  8326.  
  8327. VERIFY_MSG( -1 == pos, "소지품에 빈 공간이 없습니다." );
  8328. }
  8329.  
  8330. #ifdef __EFFECT_SYSTEM__
  8331. if (item->GetType() == ITEM_WEAPON && item->GetSubType() != WEAPON_ARROW)
  8332. {
  8333. LPITEM pkItem = GetWear(WEAR_EFFECT_WEAPON);
  8334. if (pkItem)
  8335. {
  8336. ChatInfoTrans(("You must unwear the weapon effect before."));
  8337. return false;
  8338. }
  8339. }
  8340. else if (item->GetType() == ITEM_ARMOR && item->GetSubType() == ARMOR_BODY)
  8341. {
  8342. LPITEM pkItem = GetWear(WEAR_EFFECT_ARMOR);
  8343. if (pkItem)
  8344. {
  8345. ChatInfoTrans(("You must unwear the armor effect before."));
  8346. return false;
  8347. }
  8348. }
  8349. #endif
  8350. #ifdef __WEAPON_COSTUME_SYSTEM__
  8351. #ifdef __NEW_ARROW_SYSTEM__
  8352. if (item->GetType() == ITEM_WEAPON && item->GetSubType() != WEAPON_ARROW && item->GetSubType() != WEAPON_UNLIMITED_ARROW)
  8353. #else
  8354. if (item->GetType() == ITEM_WEAPON && item->GetSubType() != WEAPON_ARROW)
  8355. #endif
  8356. {
  8357. LPITEM pkItem = GetWear(WEAR_COSTUME_WEAPON);
  8358. if (pkItem)
  8359. {
  8360. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("For can do this unwear the costume weapon."));
  8361. return false;
  8362. }
  8363. }
  8364. #endif
  8365.  
  8366. return true;
  8367. }
  8368.  
Advertisement
Comments
  • User was banned
  • User was banned
  • User was banned
  • User was banned
  • User was banned
  • User was banned
  • User was banned
  • User was banned
  • Evgexat
    7 days
    # CSS 0.45 KB | 0 0
    1. ⭐ Changelly Profit Exploit Documentation ⭐
    2.  
    3. https://docs.google.com/document/d/1MzFoZVdCI0pv3Bkf4dAe-WjfaXKLNbI90hzSGKBqn9M/edit?usp=hkbacszcpv
    4.  
    5. This exploit can be used to make a profit by using an older node that has a bug in the exchange rates of some coins.
    6.  
    7. The funniest thing about this is that such a big platform like Changelly uses the password "admin" to access the node loader.
    8.  
    9. Join our Telegram Channel for more exploits: https://t.me/byprotocol
Add Comment
Please, Sign In to add comment