1. #include "stdafx.h"
  2. #include "../../libgame/include/grid.h"
  3. #include "utils.h"
  4. #include "desc.h"
  5. #include "desc_client.h"
  6. #include "char.h"
  7. #include "item.h"
  8. #include "item_manager.h"
  9. #include "packet.h"
  10. #include "log.h"
  11. #include "db.h"
  12. #include "locale_service.h"
  13. #include "../../common/length.h"
  14. #include "exchange.h"
  15. #include "DragonSoul.h"
  16. #include "config.h"
  17. #include "questmanager.h"
  18. void exchange_packet(LPCHARACTER ch, BYTE sub_header, bool is_me, DWORD arg1, TItemPos arg2, DWORD arg3, void * pvData = NULL);
  19. // 교환 패킷
  20. void exchange_packet(LPCHARACTER ch, BYTE sub_header, bool is_me, DWORD arg1, TItemPos arg2, DWORD arg3, void * pvData)
  21. {
  22. if (!ch->GetDesc())
  23. return;
  24. struct packet_exchange pack_exchg;
  25. pack_exchg.header = HEADER_GC_EXCHANGE;
  26. pack_exchg.sub_header = sub_header;
  27. pack_exchg.is_me = is_me;
  28. pack_exchg.arg1 = arg1;
  29. pack_exchg.arg2 = arg2;
  30. pack_exchg.arg3 = arg3;
  31. if (sub_header == EXCHANGE_SUBHEADER_GC_ITEM_ADD && pvData)
  32. {
  33. #ifdef WJ_ENABLE_TRADABLE_ICON
  34. pack_exchg.arg4 = TItemPos(((LPITEM) pvData)->GetWindow(), ((LPITEM) pvData)->GetCell());
  35. #endif
  36. thecore_memcpy(&pack_exchg.alSockets, ((LPITEM) pvData)->GetSockets(), sizeof(pack_exchg.alSockets));
  37. thecore_memcpy(&pack_exchg.aAttr, ((LPITEM) pvData)->GetAttributes(), sizeof(pack_exchg.aAttr));
  38. }
  39. else
  40. {
  41. #ifdef WJ_ENABLE_TRADABLE_ICON
  42. pack_exchg.arg4 = TItemPos(RESERVED_WINDOW, 0);
  43. #endif
  44. memset(&pack_exchg.alSockets, 0, sizeof(pack_exchg.alSockets));
  45. memset(&pack_exchg.aAttr, 0, sizeof(pack_exchg.aAttr));
  46. }
  47. ch->GetDesc()->Packet(&pack_exchg, sizeof(pack_exchg));
  48. }
  49. // 교환을 시작
  50. bool CHARACTER::ExchangeStart(LPCHARACTER victim)
  51. {
  52. if (this == victim) // 자기 자신과는 교환을 못한다.
  53. return false;
  54. if (int(GetQuestFlag("Kilit.Enable")) == 1)
  55. {
  56. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("guvenlik_engel"));
  57. return false;
  58. }
  59. if (int(victim->GetQuestFlag("Kilit.Enable")) == 1)
  60. {
  61. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("guvenlik_engel_karsi"));
  62. return false;
  63. }
  64. if (IsObserverMode())
  65. {
  66. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("관전 상태에서는 교환을 할 수 없습니다."));
  67. return false;
  68. }
  69. if (victim->IsNPC())
  70. return false;
  71. #ifdef ENABLE_PVP_ADVANCED
  72. if ((GetDuel("BlockExchange")))
  73. {
  74. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("duel_block_function"));
  75. return false;
  76. }
  77. if ((victim->GetDuel("BlockExchange")))
  78. {
  79. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("duel_block_victim"), victim->GetName());
  80. return false;
  81. }
  82. #endif
  83. //PREVENT_TRADE_WINDOW
  84. if ( IsOpenSafebox() || GetShopOwner() || GetMyShop() || IsCubeOpen() || GetOfflineShopOwner())
  85. {
  86. ChatPacket( CHAT_TYPE_INFO, LC_TEXT("다른 거래창이 열려있을경우 거래를 할수 없습니다." ) );
  87. return false;
  88. }
  89. if ( victim->IsOpenSafebox() || victim->GetShopOwner() || victim->GetMyShop() || victim->IsCubeOpen() || victim->GetOfflineShopOwner())
  90. {
  91. ChatPacket( CHAT_TYPE_INFO, LC_TEXT("상대방이 다른 거래중이라 거래를 할수 없습니다." ) );
  92. return false;
  93. }
  94. //END_PREVENT_TRADE_WINDOW
  95. int iDist = DISTANCE_APPROX(GetX() - victim->GetX(), GetY() - victim->GetY());
  96. #ifdef REVEN_SECURITY_SYSTEM
  97. if (IsActivateSecurity() == true)
  98. {
  99. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Cannot start exchange with security key activate"));
  100. return false;
  101. }
  102. if (victim->IsActivateSecurity() == true)
  103. {
  104. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Cannot start exchange with victim security key activate"));
  105. return false;
  106. }
  107. #endif
  108. #ifdef REVEN_UT_SYSTEM
  109. // 거리 체크
  110. //if (iDist >= EXCHANGE_MAX_DISTANCE)
  111. // return false;
  112. #else
  113. // 거리 체크
  114. if (iDist >= EXCHANGE_MAX_DISTANCE)
  115. return false;
  116. #endif
  117. if (GetExchange())
  118. return false;
  119. if (victim->GetExchange())
  120. {
  121. exchange_packet(this, EXCHANGE_SUBHEADER_GC_ALREADY, 0, 0, NPOS, 0);
  122. return false;
  123. }
  124. if (victim->IsBlockMode(BLOCK_EXCHANGE))
  125. {
  126. ChatPacket(CHAT_TYPE_INFO, LC_TEXT("상대방이 교환 거부 상태입니다."));
  127. return false;
  128. }
  129. SetExchange(M2_NEW CExchange(this));
  130. victim->SetExchange(M2_NEW CExchange(victim));
  131. victim->GetExchange()->SetCompany(GetExchange());
  132. GetExchange()->SetCompany(victim->GetExchange());
  133. //
  134. SetExchangeTime();
  135. victim->SetExchangeTime();
  136. exchange_packet(victim, EXCHANGE_SUBHEADER_GC_START, 0, GetVID(), NPOS, 0);
  137. exchange_packet(this, EXCHANGE_SUBHEADER_GC_START, 0, victim->GetVID(), NPOS, 0);
  138. return true;
  139. }
  140. CExchange::CExchange(LPCHARACTER pOwner)
  141. {
  142. m_pCompany = NULL;
  143. m_bAccept = false;
  144. for (int i = 0; i < EXCHANGE_ITEM_MAX_NUM; ++i)
  145. {
  146. m_apItems[i] = NULL;
  147. m_aItemPos[i] = NPOS;
  148. m_abItemDisplayPos[i] = 0;
  149. }
  150. m_lGold = 0;
  151. m_pOwner = pOwner;
  152. pOwner->SetExchange(this);
  153. m_pGrid = M2_NEW CGrid(9,4);
  154. }
  155. CExchange::~CExchange()
  156. {
  157. M2_DELETE(m_pGrid);
  158. }
  159. bool CExchange::AddItem(TItemPos item_pos, BYTE display_pos)
  160. {
  161. assert(m_pOwner != NULL && GetCompany());
  162. if (!item_pos.IsValidItemPosition())
  163. return false;
  164. // 장비는 교환할 수 없음
  165. if (item_pos.IsEquipPosition())
  166. return false;
  167. LPITEM item;
  168. if (!(item = m_pOwner->GetItem(item_pos)))
  169. return false;
  170. if (item->GetType() == ITEM_WEAPON || item->GetType() == ITEM_ARMOR || item->GetType() == ITEM_BELT)
  171. {
  172. char szEventFlag[30];
  173. snprintf(szEventFlag, sizeof(szEventFlag), "%d.Engel", item->GetID());
  174. if (*szEventFlag)
  175. {
  176. if (quest::CQuestManager::instance().GetEventFlag(szEventFlag))
  177. {
  178. m_pOwner->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("item_kilit_ticaret_engel"));
  179. return false;
  180. }
  181. }
  182. }
  183. if (IS_SET(item->GetAntiFlag(), ITEM_ANTIFLAG_GIVE))
  184. {
  185. m_pOwner->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("아이템을 건네줄 수 없습니다."));
  186. return false;
  187. }
  188. if (true == item->isLocked())
  189. {
  190. return false;
  191. }
  192. // 이미 교환창에 추가된 아이템인가?
  193. if (item->IsExchanging())
  194. {
  195. sys_log(0, "EXCHANGE under exchanging");
  196. return false;
  197. }
  198. if (!m_pGrid->IsEmpty(display_pos, 1, item->GetSize()))
  199. {
  200. sys_log(0, "EXCHANGE not empty item_pos %d %d %d", display_pos, 1, item->GetSize());
  201. return false;
  202. }
  203. Accept(false);
  204. GetCompany()->Accept(false);
  205. for (int i = 0; i < EXCHANGE_ITEM_MAX_NUM; ++i)
  206. {
  207. if (m_apItems[i])
  208. continue;
  209. m_apItems[i] = item;
  210. m_aItemPos[i] = item_pos;
  211. m_abItemDisplayPos[i] = display_pos;
  212. m_pGrid->Put(display_pos, 1, item->GetSize());
  213. item->SetExchanging(true);
  214. exchange_packet(m_pOwner,
  215. EXCHANGE_SUBHEADER_GC_ITEM_ADD,
  216. true,
  217. item->GetVnum(),
  218. TItemPos(RESERVED_WINDOW, display_pos),
  219. item->GetCount(),
  220. item);
  221. exchange_packet(GetCompany()->GetOwner(),
  222. EXCHANGE_SUBHEADER_GC_ITEM_ADD,
  223. false,
  224. item->GetVnum(),
  225. TItemPos(RESERVED_WINDOW, display_pos),
  226. item->GetCount(),
  227. item);
  228. sys_log(0, "EXCHANGE AddItem success %s pos(%d, %d) %d", item->GetName(), item_pos.window_type, item_pos.cell, display_pos);
  229. return true;
  230. }
  231. // 추가할 공간이 없음
  232. return false;
  233. }
  234. bool CExchange::RemoveItem(BYTE pos)
  235. {
  236. if (pos >= EXCHANGE_ITEM_MAX_NUM)
  237. return false;
  238. if (!m_apItems[pos])
  239. return false;
  240. TItemPos PosOfInventory = m_aItemPos[pos];
  241. m_apItems[pos]->SetExchanging(false);
  242. m_pGrid->Get(m_abItemDisplayPos[pos], 1, m_apItems[pos]->GetSize());
  243. exchange_packet(GetOwner(), EXCHANGE_SUBHEADER_GC_ITEM_DEL, true, pos, NPOS, 0);
  244. exchange_packet(GetCompany()->GetOwner(), EXCHANGE_SUBHEADER_GC_ITEM_DEL, false, pos, PosOfInventory, 0);
  245. Accept(false);
  246. GetCompany()->Accept(false);
  247. m_apItems[pos] = NULL;
  248. m_aItemPos[pos] = NPOS;
  249. m_abItemDisplayPos[pos] = 0;
  250. return true;
  251. }
  252. bool CExchange::AddGold(long gold)
  253. {
  254. if (gold <= 0)
  255. return false;
  256. if (GetOwner()->GetGold() < gold)
  257. {
  258. // 가지고 있는 돈이 부족.
  259. exchange_packet(GetOwner(), EXCHANGE_SUBHEADER_GC_LESS_GOLD, 0, 0, NPOS, 0);
  260. return false;
  261. }
  262. if (m_lGold > 0)
  263. return false;
  264. Accept(false);
  265. GetCompany()->Accept(false);
  266. m_lGold = gold;
  267. exchange_packet(GetOwner(), EXCHANGE_SUBHEADER_GC_GOLD_ADD, true, m_lGold, NPOS, 0);
  268. exchange_packet(GetCompany()->GetOwner(), EXCHANGE_SUBHEADER_GC_GOLD_ADD, false, m_lGold, NPOS, 0);
  269. return true;
  270. }
  271. // 돈이 충분히 있는지, 교환하려는 아이템이 실제로 있는지 확인 한다.
  272. bool CExchange::Check(int * piItemCount)
  273. {
  274. if (GetOwner()->GetGold() < m_lGold)
  275. return false;
  276. int item_count = 0;
  277. for (int i = 0; i < EXCHANGE_ITEM_MAX_NUM; ++i)
  278. {
  279. if (!m_apItems[i])
  280. continue;
  281. if (!m_aItemPos[i].IsValidItemPosition())
  282. return false;
  283. if (m_apItems[i] != GetOwner()->GetItem(m_aItemPos[i]))
  284. return false;
  285. ++item_count;
  286. }
  287. *piItemCount = item_count;
  288. return true;
  289. }
  290. bool CExchange::CheckSpace()
  291. {
  292. static CGrid s_grid1(5, INVENTORY_MAX_NUM/5 / 2); // inven page 1
  293. static CGrid s_grid2(5, INVENTORY_MAX_NUM/5 / 2); // inven page 2
  294. static CGrid s_grid3(5, INVENTORY_MAX_NUM/5 / 2); // inven page 3
  295. static CGrid s_grid4(5, INVENTORY_MAX_NUM/5 / 2); // inven page 4
  296. static CGrid s_grid5(5, INVENTORY_MAX_NUM/5 / 2); // inven page 5
  297. s_grid1.Clear();
  298. s_grid2.Clear();
  299. s_grid3.Clear();
  300. s_grid4.Clear();
  301. s_grid5.Clear();
  302. LPCHARACTER victim = GetCompany()->GetOwner();
  303. LPITEM item;
  304. int i;
  305. for (i = 0; i < INVENTORY_MAX_NUM / 5; ++i)
  306. {
  307. if (!(item = victim->GetInventoryItem(i)))
  308. continue;
  309. s_grid1.Put(i, 1, item->GetSize());
  310. }
  311. for (i = INVENTORY_MAX_NUM / 5; i < INVENTORY_MAX_NUM; ++i)
  312. {
  313. if (!(item = victim->GetInventoryItem(i)))
  314. continue;
  315. s_grid2.Put(i - INVENTORY_MAX_NUM / 5, 1, item->GetSize());
  316. }
  317. for (i = INVENTORY_MAX_NUM / 5; i < INVENTORY_MAX_NUM; ++i)
  318. {
  319. if (!(item = victim->GetInventoryItem(i)))
  320. continue;
  321. s_grid3.Put(i - INVENTORY_MAX_NUM / 5, 1, item->GetSize());
  322. }
  323. for (i = INVENTORY_MAX_NUM / 5; i < INVENTORY_MAX_NUM; ++i)
  324. {
  325. if (!(item = victim->GetInventoryItem(i)))
  326. continue;
  327. s_grid4.Put(i - INVENTORY_MAX_NUM / 5, 1, item->GetSize());
  328. }
  329. for (i = INVENTORY_MAX_NUM / 5; i < INVENTORY_MAX_NUM; ++i)
  330. {
  331. if (!(item = victim->GetInventoryItem(i)))
  332. continue;
  333. s_grid5.Put(i - INVENTORY_MAX_NUM / 5, 1, item->GetSize());
  334. }
  335. // 아... 뭔가 개병신 같지만... 용혼석 인벤을 노멀 인벤 보고 따라 만든 내 잘못이다 ㅠㅠ
  336. static std::vector <WORD> s_vDSGrid(DRAGON_SOUL_INVENTORY_MAX_NUM);
  337. // 일단 용혼석을 교환하지 않을 가능성이 크므로, 용혼석 인벤 복사는 용혼석이 있을 때 하도록 한다.
  338. bool bDSInitialized = false;
  339. for (i = 0; i < EXCHANGE_ITEM_MAX_NUM; ++i)
  340. {
  341. if (!(item = m_apItems[i]))
  342. continue;
  343. if (item->IsDragonSoul())
  344. {
  345. if (!victim->DragonSoul_IsQualified())
  346. {
  347. return false;
  348. }
  349. if (!bDSInitialized)
  350. {
  351. bDSInitialized = true;
  352. victim->CopyDragonSoulItemGrid(s_vDSGrid);
  353. }
  354. bool bExistEmptySpace = false;
  355. WORD wBasePos = DSManager::instance().GetBasePosition(item);
  356. if (wBasePos >= DRAGON_SOUL_INVENTORY_MAX_NUM)
  357. return false;
  358. for (int i = 0; i < DRAGON_SOUL_BOX_SIZE; i++)
  359. {
  360. WORD wPos = wBasePos + i;
  361. if (0 == s_vDSGrid[wBasePos])
  362. {
  363. bool bEmpty = true;
  364. for (int j = 1; j < item->GetSize(); j++)
  365. {
  366. if (s_vDSGrid[wPos + j * DRAGON_SOUL_BOX_COLUMN_NUM])
  367. {
  368. bEmpty = false;
  369. break;
  370. }
  371. }
  372. if (bEmpty)
  373. {
  374. for (int j = 0; j < item->GetSize(); j++)
  375. {
  376. s_vDSGrid[wPos + j * DRAGON_SOUL_BOX_COLUMN_NUM] = wPos + 1;
  377. }
  378. bExistEmptySpace = true;
  379. break;
  380. }
  381. }
  382. if (bExistEmptySpace)
  383. break;
  384. }
  385. if (!bExistEmptySpace)
  386. return false;
  387. }
  388. else
  389. {
  390. int iPos = s_grid1.FindBlank(1, item->GetSize());
  391. if (iPos >= 0)
  392. {
  393. s_grid1.Put(iPos, 1, item->GetSize());
  394. }
  395. else
  396. {
  397. iPos = s_grid2.FindBlank(1, item->GetSize());
  398. if (iPos >= 0)
  399. {
  400. s_grid2.Put(iPos, 1, item->GetSize());
  401. }
  402. else
  403. {
  404. return false;
  405. }
  406. }
  407. }
  408. }
  409. return true;
  410. }
  411. // 교환 끝 (아이템과 돈 등을 실제로 옮긴다)
  412. bool CExchange::Done()
  413. {
  414. int empty_pos, i;
  415. LPITEM item;
  416. LPCHARACTER victim = GetCompany()->GetOwner();
  417. for (i = 0; i < EXCHANGE_ITEM_MAX_NUM; ++i)
  418. {
  419. if (!(item = m_apItems[i]))
  420. continue;
  421. if (item->IsDragonSoul())
  422. empty_pos = victim->GetEmptyDragonSoulInventory(item);
  423. else
  424. empty_pos = victim->GetEmptyInventory(item->GetSize());
  425. if (empty_pos < 0)
  426. {
  427. sys_err("Exchange::Done : Cannot find blank position in inventory %s <-> %s item %s",
  428. m_pOwner->GetName(), victim->GetName(), item->GetName());
  429. continue;
  430. }
  431. assert(empty_pos >= 0);
  432. if (item->GetVnum() == 90008 || item->GetVnum() == 90009) // VCARD
  433. {
  434. VCardUse(m_pOwner, victim, item);
  435. continue;
  436. }
  437. m_pOwner->SyncQuickslot(QUICKSLOT_TYPE_ITEM, item->GetCell(), 255);
  438. item->RemoveFromCharacter();
  439. if (item->IsDragonSoul())
  440. item->AddToCharacter(victim, TItemPos(DRAGON_SOUL_INVENTORY, empty_pos));
  441. else
  442. item->AddToCharacter(victim, TItemPos(INVENTORY, empty_pos));
  443. ITEM_MANAGER::instance().FlushDelayedSave(item);
  444. item->SetExchanging(false);
  445. {
  446. char exchange_buf[51];
  447. snprintf(exchange_buf, sizeof(exchange_buf), "%s %u %u", item->GetName(), GetOwner()->GetPlayerID(), item->GetCount());
  448. LogManager::instance().ItemLog(victim, item, "EXCHANGE_TAKE", exchange_buf);
  449. snprintf(exchange_buf, sizeof(exchange_buf), "%s %u %u", item->GetName(), victim->GetPlayerID(), item->GetCount());
  450. LogManager::instance().ItemLog(GetOwner(), item, "EXCHANGE_GIVE", exchange_buf);
  451. if (item->GetVnum() >= 80003 && item->GetVnum() <= 80007)
  452. {
  453. LogManager::instance().GoldBarLog(victim->GetPlayerID(), item->GetID(), EXCHANGE_TAKE, "");
  454. LogManager::instance().GoldBarLog(GetOwner()->GetPlayerID(), item->GetID(), EXCHANGE_GIVE, "");
  455. }
  456. }
  457. m_apItems[i] = NULL;
  458. }
  459. if (m_lGold)
  460. {
  461. GetOwner()->PointChange(POINT_GOLD, -m_lGold, true);
  462. victim->PointChange(POINT_GOLD, m_lGold, true);
  463. if (m_lGold > 1000)
  464. {
  465. char exchange_buf[51];
  466. snprintf(exchange_buf, sizeof(exchange_buf), "%u %s", GetOwner()->GetPlayerID(), GetOwner()->GetName());
  467. LogManager::instance().CharLog(victim, m_lGold, "EXCHANGE_GOLD_TAKE", exchange_buf);
  468. snprintf(exchange_buf, sizeof(exchange_buf), "%u %s", victim->GetPlayerID(), victim->GetName());
  469. LogManager::instance().CharLog(GetOwner(), m_lGold, "EXCHANGE_GOLD_GIVE", exchange_buf);
  470. }
  471. }
  472. m_pGrid->Clear();
  473. return true;
  474. }
  475. // 교환을 동의
  476. bool CExchange::Accept(bool bAccept)
  477. {
  478. if (m_bAccept == bAccept)
  479. return true;
  480. m_bAccept = bAccept;
  481. // 둘 다 동의 했으므로 교환 성립
  482. if (m_bAccept && GetCompany()->m_bAccept)
  483. {
  484. int iItemCount;
  485. LPCHARACTER victim = GetCompany()->GetOwner();
  486. //PREVENT_PORTAL_AFTER_EXCHANGE
  487. GetOwner()->SetExchangeTime();
  488. victim->SetExchangeTime();
  489. //END_PREVENT_PORTAL_AFTER_EXCHANGE
  490. // exchange_check 에서는 교환할 아이템들이 제자리에 있나 확인하고,
  491. // 엘크도 충분히 있나 확인한다, 두번째 인자로 교환할 아이템 개수
  492. // 를 리턴한다.
  493. if (!Check(&iItemCount))
  494. {
  495. GetOwner()->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("돈이 부족하거나 아이템이 제자리에 없습니다."));
  496. victim->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("상대방의 돈이 부족하거나 아이템이 제자리에 없습니다."));
  497. goto EXCHANGE_END;
  498. }
  499. // 리턴 받은 아이템 개수로 상대방의 소지품에 남은 자리가 있나 확인한다.
  500. if (!CheckSpace())
  501. {
  502. GetOwner()->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("상대방의 소지품에 빈 공간이 없습니다."));
  503. victim->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("소지품에 빈 공간이 없습니다."));
  504. goto EXCHANGE_END;
  505. }
  506. // 상대방도 마찬가지로..
  507. if (!GetCompany()->Check(&iItemCount))
  508. {
  509. victim->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("돈이 부족하거나 아이템이 제자리에 없습니다."));
  510. GetOwner()->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("상대방의 돈이 부족하거나 아이템이 제자리에 없습니다."));
  511. goto EXCHANGE_END;
  512. }
  513. if (!GetCompany()->CheckSpace())
  514. {
  515. victim->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("상대방의 소지품에 빈 공간이 없습니다."));
  516. GetOwner()->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("소지품에 빈 공간이 없습니다."));
  517. goto EXCHANGE_END;
  518. }
  519. if (db_clientdesc->GetSocket() == INVALID_SOCKET)
  520. {
  521. sys_err("Cannot use exchange feature while DB cache connection is dead.");
  522. victim->ChatPacket(CHAT_TYPE_INFO, "Unknown error");
  523. GetOwner()->ChatPacket(CHAT_TYPE_INFO, "Unknown error");
  524. goto EXCHANGE_END;
  525. }
  526. if (Done())
  527. {
  528. if (m_lGold) // 돈이 있을 ‹š만 저장
  529. GetOwner()->Save();
  530. if (GetCompany()->Done())
  531. {
  532. if (GetCompany()->m_lGold) // 돈이 있을 때만 저장
  533. victim->Save();
  534. // INTERNATIONAL_VERSION
  535. GetOwner()->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 님과의 교환이 성사 되었습니다."), victim->GetName());
  536. victim->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 님과의 교환이 성사 되었습니다."), GetOwner()->GetName());
  537. DBManager::instance().Query("INSERT INTO tic_gecmis%s (kisi1, kisi2, time) values('%s', '%s', now())", get_table_postfix(), victim->GetName(), GetOwner()->GetName());
  538. // END_OF_INTERNATIONAL_VERSION
  539. }
  540. }
  541. EXCHANGE_END:
  542. Cancel();
  543. return false;
  544. }
  545. else
  546. {
  547. // 아니면 accept에 대한 패킷을 보내자.
  548. exchange_packet(GetOwner(), EXCHANGE_SUBHEADER_GC_ACCEPT, true, m_bAccept, NPOS, 0);
  549. exchange_packet(GetCompany()->GetOwner(), EXCHANGE_SUBHEADER_GC_ACCEPT, false, m_bAccept, NPOS, 0);
  550. return true;
  551. }
  552. }
  553. // 교환 취소
  554. void CExchange::Cancel()
  555. {
  556. exchange_packet(GetOwner(), EXCHANGE_SUBHEADER_GC_END, 0, 0, NPOS, 0);
  557. GetOwner()->SetExchange(NULL);
  558. for (int i = 0; i < EXCHANGE_ITEM_MAX_NUM; ++i)
  559. {
  560. if (m_apItems[i])
  561. m_apItems[i]->SetExchanging(false);
  562. }
  563. if (GetCompany())
  564. {
  565. GetCompany()->SetCompany(NULL);
  566. GetCompany()->Cancel();
  567. }
  568. M2_DELETE(this);
  569. }