Guest User

Untitled

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