Advertisement
jegarba

shop_manager.cpp

Sep 18th, 2020
542
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.35 KB | None | 0 0
  1. #include "stdafx.h"
  2. #include "../../libgame/include/grid.h"
  3. #include "constants.h"
  4. #include "utils.h"
  5. #include "config.h"
  6. #include "shop.h"
  7. #include "desc.h"
  8. #include "desc_manager.h"
  9. #include "char.h"
  10. #include "char_manager.h"
  11. #include "item.h"
  12. #include "item_manager.h"
  13. #include "buffer_manager.h"
  14. #include "packet.h"
  15. #include "log.h"
  16. #include "db.h"
  17. #include "questmanager.h"
  18. #include "monarch.h"
  19. #include "mob_manager.h"
  20. #include "locale_service.h"
  21. #include "desc_client.h"
  22. #include "shop_manager.h"
  23. #include "group_text_parse_tree.h"
  24. #include "shopEx.h"
  25. #include <boost/algorithm/string/predicate.hpp>
  26. #include "shop_manager.h"
  27. #include <cctype>
  28.  
  29. CShopManager::CShopManager()
  30. {
  31. }
  32.  
  33. CShopManager::~CShopManager()
  34. {
  35. Destroy();
  36. }
  37.  
  38. bool CShopManager::Initialize(TShopTable * table, int size)
  39. {
  40. if (!m_map_pkShop.empty())
  41. {
  42. for (TShopMap::iterator it = m_map_pkShop.begin(); it != m_map_pkShop.end(); it++)
  43. {
  44. it->second->RemoveAllGuests();
  45. }
  46. }
  47.  
  48. m_map_pkShop.clear();
  49. m_map_pkShopByNPCVnum.clear();
  50.  
  51. int i;
  52.  
  53. for (i = 0; i < size; ++i, ++table)
  54. {
  55. LPSHOP shop = M2_NEW CShop;
  56.  
  57. if (!shop->Create(table->dwVnum, table->dwNPCVnum, table->items))
  58. {
  59. M2_DELETE(shop);
  60. continue;
  61. }
  62.  
  63. m_map_pkShop.insert(TShopMap::value_type(table->dwVnum, shop));
  64. m_map_pkShopByNPCVnum.insert(TShopMap::value_type(table->dwNPCVnum, shop));
  65. }
  66. char szShopTableExFileName[256];
  67.  
  68. snprintf(szShopTableExFileName, sizeof(szShopTableExFileName),
  69. "%s/shop_table_ex.txt", LocaleService_GetBasePath().c_str());
  70.  
  71. return ReadShopTableEx(szShopTableExFileName);
  72. }
  73.  
  74. void CShopManager::Destroy()
  75. {
  76. TShopMap::iterator it = m_map_pkShop.begin();
  77.  
  78. while (it != m_map_pkShop.end())
  79. {
  80. M2_DELETE(it->second);
  81. ++it;
  82. }
  83.  
  84. m_map_pkShop.clear();
  85. }
  86.  
  87. LPSHOP CShopManager::Get(DWORD dwVnum)
  88. {
  89. TShopMap::const_iterator it = m_map_pkShop.find(dwVnum);
  90.  
  91. if (it == m_map_pkShop.end())
  92. return NULL;
  93.  
  94. return (it->second);
  95. }
  96.  
  97. LPSHOP CShopManager::GetByNPCVnum(DWORD dwVnum)
  98. {
  99. TShopMap::const_iterator it = m_map_pkShopByNPCVnum.find(dwVnum);
  100.  
  101. if (it == m_map_pkShopByNPCVnum.end())
  102. return NULL;
  103.  
  104. return (it->second);
  105. }
  106.  
  107. /*
  108. * 인터페이스 함수들
  109. */
  110.  
  111. // 상점 거래를 시작
  112. bool CShopManager::StartShopping(LPCHARACTER pkChr, LPCHARACTER pkChrShopKeeper, int iShopVnum)
  113. {
  114. if (pkChr->GetShopOwner() == pkChrShopKeeper)
  115. return false;
  116. // this method is only for NPC
  117. if (pkChrShopKeeper->IsPC())
  118. return false;
  119.  
  120. //PREVENT_TRADE_WINDOW
  121. if (pkChr->IsOpenSafebox() || pkChr->GetExchange() || pkChr->GetMyShop() || pkChr->IsCubeOpen())
  122. {
  123. pkChr->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("다른 거래창이 열린상태에서는 상점거래를 할수 가 없습니다."));
  124. return false;
  125. }
  126. //END_PREVENT_TRADE_WINDOW
  127.  
  128. long distance = DISTANCE_APPROX(pkChr->GetX() - pkChrShopKeeper->GetX(), pkChr->GetY() - pkChrShopKeeper->GetY());
  129.  
  130. if (distance >= SHOP_MAX_DISTANCE)
  131. {
  132. sys_log(1, "SHOP: TOO_FAR: %s distance %d", pkChr->GetName(), distance);
  133. return false;
  134. }
  135.  
  136. LPSHOP pkShop;
  137.  
  138. if (iShopVnum)
  139. pkShop = Get(iShopVnum);
  140. else
  141. pkShop = GetByNPCVnum(pkChrShopKeeper->GetRaceNum());
  142.  
  143. if (!pkShop)
  144. {
  145. sys_log(1, "SHOP: NO SHOP");
  146. return false;
  147. }
  148.  
  149. bool bOtherEmpire = false;
  150.  
  151. if (pkChr->GetEmpire() != pkChrShopKeeper->GetEmpire())
  152. bOtherEmpire = true;
  153.  
  154. pkShop->AddGuest(pkChr, pkChrShopKeeper->GetVID(), bOtherEmpire);
  155. pkChr->SetShopOwner(pkChrShopKeeper);
  156. sys_log(0, "SHOP: START: %s", pkChr->GetName());
  157. return true;
  158. }
  159.  
  160. LPSHOP CShopManager::FindPCShop(DWORD dwVID)
  161. {
  162. TShopMap::iterator it = m_map_pkShopByPC.find(dwVID);
  163.  
  164. if (it == m_map_pkShopByPC.end())
  165. return NULL;
  166.  
  167. return it->second;
  168. }
  169.  
  170. LPSHOP CShopManager::CreatePCShop(LPCHARACTER ch, TShopItemTable * pTable, BYTE bItemCount)
  171. {
  172. if (FindPCShop(ch->GetVID()))
  173. return NULL;
  174.  
  175. LPSHOP pkShop = M2_NEW CShop;
  176. pkShop->SetPCShop(ch);
  177. pkShop->SetShopItems(pTable, bItemCount);
  178.  
  179. m_map_pkShopByPC.insert(TShopMap::value_type(ch->GetVID(), pkShop));
  180. return pkShop;
  181. }
  182.  
  183. void CShopManager::DestroyPCShop(LPCHARACTER ch)
  184. {
  185. LPSHOP pkShop = FindPCShop(ch->GetVID());
  186.  
  187. if (!pkShop)
  188. return;
  189.  
  190. //PREVENT_ITEM_COPY;
  191. ch->SetMyShopTime();
  192. //END_PREVENT_ITEM_COPY
  193.  
  194. m_map_pkShopByPC.erase(ch->GetVID());
  195. M2_DELETE(pkShop);
  196. }
  197.  
  198. // 상점 거래를 종료
  199. void CShopManager::StopShopping(LPCHARACTER ch)
  200. {
  201. LPSHOP shop;
  202.  
  203. if (!(shop = ch->GetShop()))
  204. return;
  205.  
  206. //PREVENT_ITEM_COPY;
  207. ch->SetMyShopTime();
  208. //END_PREVENT_ITEM_COPY
  209.  
  210. shop->RemoveGuest(ch);
  211. sys_log(0, "SHOP: END: %s", ch->GetName());
  212. }
  213.  
  214. // 아이템 구입
  215. void CShopManager::Buy(LPCHARACTER ch, BYTE pos)
  216. {
  217. if (!ch->GetShop())
  218. return;
  219.  
  220. if (!ch->GetShopOwner())
  221. return;
  222.  
  223. if (DISTANCE_APPROX(ch->GetX() - ch->GetShopOwner()->GetX(), ch->GetY() - ch->GetShopOwner()->GetY()) > 2000)
  224. {
  225. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("상점과의 거리가 너무 멀어 물건을 살 수 없습니다."));
  226. return;
  227. }
  228.  
  229. CShop* pkShop = ch->GetShop();
  230.  
  231. if (!pkShop->IsPCShop())
  232. {
  233. //if (pkShop->GetVnum() == 0)
  234. // return;
  235. //const CMob* pkMob = CMobManager::instance().Get(pkShop->GetNPCVnum());
  236. //if (!pkMob)
  237. // return;
  238.  
  239. //if (pkMob->m_table.bType != CHAR_TYPE_NPC)
  240. //{
  241. // return;
  242. //}
  243. }
  244. else
  245. {
  246. }
  247.  
  248. //PREVENT_ITEM_COPY
  249. ch->SetMyShopTime();
  250. //END_PREVENT_ITEM_COPY
  251.  
  252. int ret = pkShop->Buy(ch, pos);
  253.  
  254. if (SHOP_SUBHEADER_GC_OK != ret) // 문제가 있었으면 보낸다.
  255. {
  256. TPacketGCShop pack;
  257.  
  258. pack.header = HEADER_GC_SHOP;
  259. pack.subheader = ret;
  260. pack.size = sizeof(TPacketGCShop);
  261.  
  262. ch->GetDesc()->Packet(&pack, sizeof(pack));
  263. }
  264. }
  265.  
  266. void CShopManager::Sell(LPCHARACTER ch, BYTE bCell, BYTE bCount)
  267. {
  268. if (!ch->GetShop())
  269. return;
  270.  
  271. if (!ch->GetShopOwner())
  272. return;
  273.  
  274. if (!ch->CanHandleItem())
  275. return;
  276.  
  277. if (ch->GetShop()->IsPCShop())
  278. return;
  279.  
  280. if (DISTANCE_APPROX(ch->GetX()-ch->GetShopOwner()->GetX(), ch->GetY()-ch->GetShopOwner()->GetY())>2000)
  281. {
  282. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("상점과의 거리가 너무 멀어 물건을 팔 수 없습니다."));
  283. return;
  284. }
  285.  
  286. LPITEM item = ch->GetInventoryItem(bCell);
  287.  
  288. if (!item)
  289. return;
  290.  
  291. if (item->IsEquipped() == true)
  292. {
  293. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("착용 중인 아이템은 판매할 수 없습니다."));
  294. return;
  295. }
  296.  
  297. if (true == item->isLocked())
  298. {
  299. return;
  300. }
  301.  
  302. if (IS_SET(item->GetAntiFlag(), ITEM_ANTIFLAG_SELL))
  303. return;
  304.  
  305. DWORD dwPrice;
  306.  
  307. if (bCount == 0 || bCount > item->GetCount())
  308. bCount = item->GetCount();
  309.  
  310. dwPrice = item->GetShopBuyPrice();
  311.  
  312. if (IS_SET(item->GetFlag(), ITEM_FLAG_COUNT_PER_1GOLD))
  313. {
  314. if (dwPrice == 0)
  315. dwPrice = bCount;
  316. else
  317. dwPrice = bCount / dwPrice;
  318. }
  319. else
  320. dwPrice *= bCount;
  321.  
  322. dwPrice /= 5;
  323.  
  324. //세금 계산
  325. DWORD dwTax = 0;
  326. int iVal = 0;
  327.  
  328. {
  329. dwTax = dwPrice * iVal/100;
  330. dwPrice -= dwTax;
  331. }
  332.  
  333. if (test_server)
  334. sys_log(0, "Sell Item price id %d %s itemid %d", ch->GetPlayerID(), ch->GetName(), item->GetID());
  335.  
  336. const int64_t nTotalMoney = static_cast<int64_t>(ch->GetGold()) + static_cast<int64_t>(dwPrice);
  337.  
  338. if (GOLD_MAX <= nTotalMoney)
  339. {
  340. sys_err("[OVERFLOW_GOLD] id %u name %s gold %u", ch->GetPlayerID(), ch->GetName(), ch->GetGold());
  341. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("20억냥이 초과하여 물품을 팔수 없습니다."));
  342. return;
  343. }
  344.  
  345. // 20050802.myevan.상점 판매 로그에 아이템 ID 추가
  346. sys_log(0, "SHOP: SELL: %s item name: %s(x%d):%u price: %u", ch->GetName(), item->GetName(), bCount, item->GetID(), dwPrice);
  347.  
  348. if (iVal > 0)
  349. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("판매금액의 %d %% 가 세금으로 나가게됩니다"), iVal);
  350.  
  351. DBManager::instance().SendMoneyLog(MONEY_LOG_SHOP, item->GetVnum(), dwPrice);
  352.  
  353. if (bCount == item->GetCount())
  354. ITEM_MANAGER::instance().RemoveItem(item, "SELL");
  355. else
  356. item->SetCount(item->GetCount() - bCount);
  357.  
  358. //군주 시스템 : 세금 징수
  359. CMonarch::instance().SendtoDBAddMoney(dwTax, ch->GetEmpire(), ch);
  360.  
  361. ch->PointChange(POINT_GOLD, dwPrice, false);
  362. }
  363.  
  364. bool CompareShopItemName(const SShopItemTable& lhs, const SShopItemTable& rhs)
  365. {
  366. TItemTable* lItem = ITEM_MANAGER::instance().GetTable(lhs.vnum);
  367. TItemTable* rItem = ITEM_MANAGER::instance().GetTable(rhs.vnum);
  368. if (lItem && rItem)
  369. return strcmp(lItem->szLocaleName, rItem->szLocaleName) < 0;
  370. else
  371. return true;
  372. }
  373.  
  374. bool ConvertToShopItemTable(IN CGroupNode* pNode, OUT TShopTableEx& shopTable)
  375. {
  376. if (!pNode->GetValue("vnum", 0, shopTable.dwVnum))
  377. {
  378. sys_err("Group %s does not have vnum.", pNode->GetNodeName().c_str());
  379. return false;
  380. }
  381.  
  382. if (!pNode->GetValue("name", 0, shopTable.name))
  383. {
  384. sys_err("Group %s does not have name.", pNode->GetNodeName().c_str());
  385. return false;
  386. }
  387.  
  388. if (shopTable.name.length() >= SHOP_TAB_NAME_MAX)
  389. {
  390. sys_err("Shop name length must be less than %d. Error in Group %s, name %s", SHOP_TAB_NAME_MAX, pNode->GetNodeName().c_str(), shopTable.name.c_str());
  391. return false;
  392. }
  393.  
  394. std::string stCoinType;
  395. if (!pNode->GetValue("cointype", 0, stCoinType))
  396. {
  397. stCoinType = "Gold";
  398. }
  399.  
  400. if (boost::iequals(stCoinType, "Gold"))
  401. {
  402. shopTable.coinType = SHOP_COIN_TYPE_GOLD;
  403. }
  404. else if (boost::iequals(stCoinType, "SecondaryCoin"))
  405. {
  406. shopTable.coinType = SHOP_COIN_TYPE_SECONDARY_COIN;
  407. }
  408. else
  409. {
  410. sys_err("Group %s has undefine cointype(%s).", pNode->GetNodeName().c_str(), stCoinType.c_str());
  411. return false;
  412. }
  413.  
  414. CGroupNode* pItemGroup = pNode->GetChildNode("items");
  415. if (!pItemGroup)
  416. {
  417. sys_err("Group %s does not have 'group items'.", pNode->GetNodeName().c_str());
  418. return false;
  419. }
  420.  
  421. int itemGroupSize = pItemGroup->GetRowCount();
  422. std::vector <TShopItemTable> shopItems(itemGroupSize);
  423. if (itemGroupSize >= SHOP_HOST_ITEM_MAX_NUM)
  424. {
  425. sys_err("count(%d) of rows of group items of group %s must be smaller than %d", itemGroupSize, pNode->GetNodeName().c_str(), SHOP_HOST_ITEM_MAX_NUM);
  426. return false;
  427. }
  428.  
  429. for (int i = 0; i < itemGroupSize; i++)
  430. {
  431. if (!pItemGroup->GetValue(i, "vnum", shopItems[i].vnum))
  432. {
  433. sys_err("row(%d) of group items of group %s does not have vnum column", i, pNode->GetNodeName().c_str());
  434. return false;
  435. }
  436.  
  437. if (!pItemGroup->GetValue(i, "count", shopItems[i].count))
  438. {
  439. sys_err("row(%d) of group items of group %s does not have count column", i, pNode->GetNodeName().c_str());
  440. return false;
  441. }
  442. if (!pItemGroup->GetValue(i, "price", shopItems[i].price))
  443. {
  444. sys_err("row(%d) of group items of group %s does not have price column", i, pNode->GetNodeName().c_str());
  445. return false;
  446. }
  447. }
  448. std::string stSort;
  449. if (!pNode->GetValue("sort", 0, stSort))
  450. {
  451. stSort = "None";
  452. }
  453.  
  454. if (boost::iequals(stSort, "Asc"))
  455. {
  456. std::sort(shopItems.begin(), shopItems.end(), CompareShopItemName);
  457. }
  458. else if(boost::iequals(stSort, "Desc"))
  459. {
  460. std::sort(shopItems.rbegin(), shopItems.rend(), CompareShopItemName);
  461. }
  462.  
  463. CGrid grid = CGrid(10, 9);
  464. int iPos;
  465.  
  466. memset(&shopTable.items[0], 0, sizeof(shopTable.items));
  467.  
  468. for (size_t i = 0; i < shopItems.size(); i++)
  469. {
  470. TItemTable * item_table = ITEM_MANAGER::instance().GetTable(shopItems[i].vnum);
  471. if (!item_table)
  472. {
  473. sys_err("vnum(%d) of group items of group %s does not exist", shopItems[i].vnum, pNode->GetNodeName().c_str());
  474. return false;
  475. }
  476.  
  477. iPos = grid.FindBlank(1, item_table->bSize);
  478.  
  479. grid.Put(iPos, 1, item_table->bSize);
  480. shopTable.items[iPos] = shopItems[i];
  481. }
  482.  
  483. shopTable.byItemCount = shopItems.size();
  484. return true;
  485. }
  486.  
  487. bool CShopManager::ReadShopTableEx(const char* stFileName)
  488. {
  489. // file 유무 체크.
  490. // 없는 경우는 에러로 처리하지 않는다.
  491. FILE* fp = fopen(stFileName, "rb");
  492. if (NULL == fp)
  493. return true;
  494. fclose(fp);
  495.  
  496. CGroupTextParseTreeLoader loader;
  497. if (!loader.Load(stFileName))
  498. {
  499. sys_err("%s Load fail.", stFileName);
  500. return false;
  501. }
  502.  
  503. CGroupNode* pShopNPCGroup = loader.GetGroup("shopnpc");
  504. if (NULL == pShopNPCGroup)
  505. {
  506. sys_err("Group ShopNPC is not exist.");
  507. return false;
  508. }
  509.  
  510. typedef std::multimap <DWORD, TShopTableEx> TMapNPCshop;
  511. TMapNPCshop map_npcShop;
  512. for (int i = 0; i < pShopNPCGroup->GetRowCount(); i++)
  513. {
  514. DWORD npcVnum;
  515. std::string shopName;
  516. if (!pShopNPCGroup->GetValue(i, "npc", npcVnum) || !pShopNPCGroup->GetValue(i, "group", shopName))
  517. {
  518. sys_err("Invalid row(%d). Group ShopNPC rows must have 'npc', 'group' columns", i);
  519. return false;
  520. }
  521. std::transform(shopName.begin(), shopName.end(), shopName.begin(), (int(*)(int))std::tolower);
  522. CGroupNode* pShopGroup = loader.GetGroup(shopName.c_str());
  523. if (!pShopGroup)
  524. {
  525. sys_err("Group %s is not exist.", shopName.c_str());
  526. return false;
  527. }
  528. TShopTableEx table;
  529. if (!ConvertToShopItemTable(pShopGroup, table))
  530. {
  531. sys_err("Cannot read Group %s.", shopName.c_str());
  532. return false;
  533. }
  534. if (m_map_pkShopByNPCVnum.find(npcVnum) != m_map_pkShopByNPCVnum.end())
  535. {
  536. sys_err("%d cannot have both original shop and extended shop", npcVnum);
  537. return false;
  538. }
  539.  
  540. map_npcShop.insert(TMapNPCshop::value_type(npcVnum, table));
  541. }
  542.  
  543. for (TMapNPCshop::iterator it = map_npcShop.begin(); it != map_npcShop.end(); ++it)
  544. {
  545. DWORD npcVnum = it->first;
  546. TShopTableEx& table = it->second;
  547. if (m_map_pkShop.find(table.dwVnum) != m_map_pkShop.end())
  548. {
  549. sys_err("Shop vnum(%d) already exists", table.dwVnum);
  550. return false;
  551. }
  552. TShopMap::iterator shop_it = m_map_pkShopByNPCVnum.find(npcVnum);
  553.  
  554. LPSHOPEX pkShopEx = NULL;
  555. if (m_map_pkShopByNPCVnum.end() == shop_it)
  556. {
  557. pkShopEx = M2_NEW CShopEx;
  558. pkShopEx->Create(0, npcVnum);
  559. m_map_pkShopByNPCVnum.insert(TShopMap::value_type(npcVnum, pkShopEx));
  560. }
  561. else
  562. {
  563. pkShopEx = dynamic_cast <CShopEx*> (shop_it->second);
  564. if (NULL == pkShopEx)
  565. {
  566. sys_err("WTF!!! It can't be happend. NPC(%d) Shop is not extended version.", shop_it->first);
  567. return false;
  568. }
  569. }
  570.  
  571. if (pkShopEx->GetTabCount() >= SHOP_TAB_COUNT_MAX)
  572. {
  573. sys_err("ShopEx cannot have tab more than %d", SHOP_TAB_COUNT_MAX);
  574. return false;
  575. }
  576.  
  577. if (pkShopEx->GetVnum() != 0 && m_map_pkShop.find(pkShopEx->GetVnum()) != m_map_pkShop.end())
  578. {
  579. sys_err("Shop vnum(%d) already exist.", pkShopEx->GetVnum());
  580. return false;
  581. }
  582. m_map_pkShop.insert(TShopMap::value_type (pkShopEx->GetVnum(), pkShopEx));
  583. pkShopEx->AddShopTable(table);
  584. }
  585.  
  586. return true;
  587. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement