Guest User

char_item.cpp

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