Guest User

shop.cpp

a guest
Jul 22nd, 2023
126
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.66 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.  
  22. /* ------------------------------------------------------------------------------------ */
  23. CShop::CShop()
  24. : m_dwVnum(0), m_dwNPCVnum(0), m_pkPC(NULL)
  25. {
  26. m_pGrid = M2_NEW CGrid(5, 9);
  27. }
  28.  
  29. CShop::~CShop()
  30. {
  31. TPacketGCShop pack;
  32.  
  33. pack.header = HEADER_GC_SHOP;
  34. pack.subheader = SHOP_SUBHEADER_GC_END;
  35. pack.size = sizeof(TPacketGCShop);
  36.  
  37. Broadcast(&pack, sizeof(pack));
  38.  
  39. GuestMapType::iterator it;
  40.  
  41. it = m_map_guest.begin();
  42.  
  43. while (it != m_map_guest.end())
  44. {
  45. LPCHARACTER ch = it->first;
  46. ch->SetShop(NULL);
  47. ++it;
  48. }
  49.  
  50. M2_DELETE(m_pGrid);
  51. }
  52.  
  53. void CShop::SetPCShop(LPCHARACTER ch)
  54. {
  55. m_pkPC = ch;
  56. }
  57.  
  58. bool CShop::Create(DWORD dwVnum, DWORD dwNPCVnum, TShopItemTable * pTable)
  59. {
  60. /*
  61. if (NULL == CMobManager::instance().Get(dwNPCVnum))
  62. {
  63. sys_err("No such a npc by vnum %d", dwNPCVnum);
  64. return false;
  65. }
  66. */
  67. sys_log(0, "SHOP #%d (Shopkeeper %d)", dwVnum, dwNPCVnum);
  68.  
  69. m_dwVnum = dwVnum;
  70. m_dwNPCVnum = dwNPCVnum;
  71.  
  72. BYTE bItemCount;
  73.  
  74. for (bItemCount = 0; bItemCount < SHOP_HOST_ITEM_MAX_NUM; ++bItemCount)
  75. if (0 == (pTable + bItemCount)->vnum)
  76. break;
  77.  
  78. SetShopItems(pTable, bItemCount);
  79. return true;
  80. }
  81.  
  82. void CShop::SetShopItems(TShopItemTable * pTable, BYTE bItemCount)
  83. {
  84. if (bItemCount > SHOP_HOST_ITEM_MAX_NUM)
  85. return;
  86.  
  87. m_pGrid->Clear();
  88.  
  89. m_itemVector.resize(SHOP_HOST_ITEM_MAX_NUM);
  90. memset(&m_itemVector[0], 0, sizeof(SHOP_ITEM) * m_itemVector.size());
  91.  
  92. for (int i = 0; i < bItemCount; ++i)
  93. {
  94. LPITEM pkItem = NULL;
  95. const TItemTable * item_table;
  96.  
  97. if (m_pkPC)
  98. {
  99. pkItem = m_pkPC->GetItem(pTable->pos);
  100.  
  101. if (!pkItem)
  102. {
  103. sys_err("cannot find item on pos (%d, %d) (name: %s)", pTable->pos.window_type, pTable->pos.cell, m_pkPC->GetName());
  104. continue;
  105. }
  106.  
  107. item_table = pkItem->GetProto();
  108. }
  109. else
  110. {
  111. if (!pTable->vnum)
  112. continue;
  113.  
  114. item_table = ITEM_MANAGER::instance().GetTable(pTable->vnum);
  115. }
  116.  
  117. if (!item_table)
  118. {
  119. sys_err("Shop: no item table by item vnum #%d", pTable->vnum);
  120. continue;
  121. }
  122.  
  123. int iPos;
  124.  
  125. if (IsPCShop())
  126. {
  127. sys_log(0, "MyShop: use position %d", pTable->display_pos);
  128. iPos = pTable->display_pos;
  129. }
  130. else
  131. iPos = m_pGrid->FindBlank(1, item_table->bSize);
  132.  
  133. if (iPos < 0)
  134. {
  135. sys_err("not enough shop window");
  136. continue;
  137. }
  138.  
  139. if (!m_pGrid->IsEmpty(iPos, 1, item_table->bSize))
  140. {
  141. if (IsPCShop())
  142. {
  143. sys_err("not empty position for pc shop %s[%d]", m_pkPC->GetName(), m_pkPC->GetPlayerID());
  144. }
  145. else
  146. {
  147. sys_err("not empty position for npc shop");
  148. }
  149. continue;
  150. }
  151.  
  152. m_pGrid->Put(iPos, 1, item_table->bSize);
  153.  
  154. SHOP_ITEM & item = m_itemVector[iPos];
  155.  
  156. item.pkItem = pkItem;
  157. item.itemid = 0;
  158.  
  159. if (item.pkItem)
  160. {
  161. item.vnum = pkItem->GetVnum();
  162. item.count = pkItem->GetCount(); // PC 샵의 경우 아이템 개수는 진짜 아이템의 개수여야 한다.
  163. item.price = pTable->price; // 가격도 사용자가 정한대로..
  164. item.itemid = pkItem->GetID();
  165. }
  166. else
  167. {
  168. item.vnum = pTable->vnum;
  169. item.count = pTable->count;
  170.  
  171. if (IS_SET(item_table->dwFlags, ITEM_FLAG_COUNT_PER_1GOLD))
  172. {
  173. if (item_table->dwGold == 0)
  174. item.price = item.count;
  175. else
  176. item.price = item.count / item_table->dwGold;
  177. }
  178. else
  179. item.price = item_table->dwGold * item.count;
  180. }
  181.  
  182. char name[36];
  183. snprintf(name, sizeof(name), "%-20s(#%-5d) (x %d)", item_table->szName, (int) item.vnum, item.count);
  184.  
  185. sys_log(0, "SHOP_ITEM: %-36s PRICE %-5d", name, item.price);
  186. ++pTable;
  187. }
  188. }
  189.  
  190. int CShop::Buy(LPCHARACTER ch, BYTE pos)
  191. {
  192. if (pos >= m_itemVector.size())
  193. {
  194. sys_log(0, "Shop::Buy : invalid position %d : %s", pos, ch->GetName());
  195. return SHOP_SUBHEADER_GC_INVALID_POS;
  196. }
  197.  
  198. sys_log(0, "Shop::Buy : name %s pos %d", ch->GetName(), pos);
  199.  
  200. GuestMapType::iterator it = m_map_guest.find(ch);
  201.  
  202. if (it == m_map_guest.end())
  203. return SHOP_SUBHEADER_GC_END;
  204.  
  205. SHOP_ITEM& r_item = m_itemVector[pos];
  206.  
  207. // if (r_item.price <= 0)
  208. if (r_item.price < 0) // Fix
  209. {
  210. LogManager::instance().HackLog("SHOP_BUY_GOLD_OVERFLOW", ch);
  211. return SHOP_SUBHEADER_GC_NOT_ENOUGH_MONEY;
  212. }
  213.  
  214. LPITEM pkSelectedItem = ITEM_MANAGER::instance().Find(r_item.itemid);
  215.  
  216. if (IsPCShop())
  217. {
  218. if (!pkSelectedItem)
  219. {
  220. sys_log(0, "Shop::Buy : Critical: This user seems to be a hacker : invalid pcshop item : BuyerPID:%d SellerPID:%d",
  221. ch->GetPlayerID(),
  222. m_pkPC->GetPlayerID());
  223.  
  224. return false;
  225. }
  226.  
  227. if ((pkSelectedItem->GetOwner() != m_pkPC))
  228. {
  229. sys_log(0, "Shop::Buy : Critical: This user seems to be a hacker : invalid pcshop item : BuyerPID:%d SellerPID:%d",
  230. ch->GetPlayerID(),
  231. m_pkPC->GetPlayerID());
  232.  
  233. return false;
  234. }
  235. }
  236.  
  237. #ifdef ENABLE_REMOVE_LIMIT_GOLD
  238. unsigned long long dwPrice = r_item.price;
  239. #else
  240. DWORD dwPrice = r_item.price;
  241. #endif
  242.  
  243. if (it->second) // if other empire, price is triple
  244. dwPrice *= 3;
  245.  
  246. if (ch->GetGold() < dwPrice)
  247. {
  248. sys_log(1, "Shop::Buy : Not enough money : %s has %d, price %d", ch->GetName(), ch->GetGold(), dwPrice);
  249. return SHOP_SUBHEADER_GC_NOT_ENOUGH_MONEY;
  250. }
  251.  
  252. LPITEM item;
  253.  
  254. if (m_pkPC) // 피씨가 운영하는 샵은 피씨가 실제 아이템을 가지고있어야 한다.
  255. item = r_item.pkItem;
  256. else
  257. item = ITEM_MANAGER::instance().CreateItem(r_item.vnum, r_item.count);
  258.  
  259. if (!item)
  260. return SHOP_SUBHEADER_GC_SOLD_OUT;
  261.  
  262. if (!m_pkPC)
  263. {
  264. if (quest::CQuestManager::instance().GetEventFlag("hivalue_item_sell") == 0)
  265. {
  266. //축복의 구슬 && 만년한철 이벤트
  267. if (item->GetVnum() == 70024 || item->GetVnum() == 70035)
  268. {
  269. return SHOP_SUBHEADER_GC_END;
  270. }
  271. }
  272. }
  273.  
  274. int iEmptyPos;
  275. if (item->IsDragonSoul())
  276. {
  277. iEmptyPos = ch->GetEmptyDragonSoulInventory(item);
  278. }
  279. else
  280. {
  281. iEmptyPos = ch->GetEmptyInventory(item->GetSize());
  282. }
  283.  
  284. if (iEmptyPos < 0)
  285. {
  286. if (m_pkPC)
  287. {
  288. sys_log(1, "Shop::Buy at PC Shop : Inventory full : %s size %d", ch->GetName(), item->GetSize());
  289. return SHOP_SUBHEADER_GC_INVENTORY_FULL;
  290. }
  291. else
  292. {
  293. sys_log(1, "Shop::Buy : Inventory full : %s size %d", ch->GetName(), item->GetSize());
  294. M2_DESTROY_ITEM(item);
  295. return SHOP_SUBHEADER_GC_INVENTORY_FULL;
  296. }
  297. }
  298.  
  299. ch->PointChange(POINT_GOLD, -dwPrice, false);
  300.  
  301. //세금 계산
  302. DWORD dwTax = 0;
  303. int iVal = 0;
  304.  
  305. if (LC_IsYMIR() || LC_IsKorea())
  306. {
  307. if (0 < (iVal = quest::CQuestManager::instance().GetEventFlag("trade_tax")))
  308. {
  309. if (iVal > 100)
  310. iVal = 100;
  311.  
  312. dwTax = dwPrice * iVal / 100;
  313. dwPrice = dwPrice - dwTax;
  314. }
  315. else
  316. {
  317. iVal = 3;
  318. dwTax = dwPrice * iVal / 100;
  319. dwPrice = dwPrice - dwTax;
  320. }
  321. }
  322. else
  323. {
  324. iVal = quest::CQuestManager::instance().GetEventFlag("personal_shop");
  325.  
  326. if (0 < iVal)
  327. {
  328. if (iVal > 100)
  329. iVal = 100;
  330.  
  331. dwTax = dwPrice * iVal / 100;
  332. dwPrice = dwPrice - dwTax;
  333. }
  334. else
  335. {
  336. iVal = 0;
  337. dwTax = 0;
  338. }
  339. }
  340.  
  341. // 상점에서 살‹š 세금 5%
  342. if (!m_pkPC)
  343. {
  344. CMonarch::instance().SendtoDBAddMoney(dwTax, ch->GetEmpire(), ch);
  345. }
  346.  
  347. // 군주 시스템 : 세금 징수
  348. if (m_pkPC)
  349. {
  350. m_pkPC->SyncQuickslot(QUICKSLOT_TYPE_ITEM, item->GetCell(), 255);
  351.  
  352. if (item->GetVnum() == 90008 || item->GetVnum() == 90009) // VCARD
  353. {
  354. VCardUse(m_pkPC, ch, item);
  355. item = NULL;
  356. }
  357. else
  358. {
  359. char buf[512];
  360.  
  361. if (item->GetVnum() >= 80003 && item->GetVnum() <= 80007)
  362. {
  363. snprintf(buf, sizeof(buf), "%s FROM: %u TO: %u PRICE: %u", item->GetName(), ch->GetPlayerID(), m_pkPC->GetPlayerID(), dwPrice);
  364. LogManager::instance().GoldBarLog(ch->GetPlayerID(), item->GetID(), SHOP_BUY, buf);
  365. LogManager::instance().GoldBarLog(m_pkPC->GetPlayerID(), item->GetID(), SHOP_SELL, buf);
  366. }
  367.  
  368. item->RemoveFromCharacter();
  369. if (item->IsDragonSoul())
  370. item->AddToCharacter(ch, TItemPos(DRAGON_SOUL_INVENTORY, iEmptyPos));
  371. else
  372. item->AddToCharacter(ch, TItemPos(INVENTORY, iEmptyPos));
  373. ITEM_MANAGER::instance().FlushDelayedSave(item);
  374.  
  375.  
  376. snprintf(buf, sizeof(buf), "%s %u(%s) %u %u", item->GetName(), m_pkPC->GetPlayerID(), m_pkPC->GetName(), dwPrice, item->GetCount());
  377. LogManager::instance().ItemLog(ch, item, "SHOP_BUY", buf);
  378.  
  379. snprintf(buf, sizeof(buf), "%s %u(%s) %u %u", item->GetName(), ch->GetPlayerID(), ch->GetName(), dwPrice, item->GetCount());
  380. LogManager::instance().ItemLog(m_pkPC, item, "SHOP_SELL", buf);
  381. }
  382.  
  383. r_item.pkItem = NULL;
  384. BroadcastUpdateItem(pos);
  385.  
  386. m_pkPC->PointChange(POINT_GOLD, dwPrice, false);
  387.  
  388. if (iVal > 0)
  389. m_pkPC->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("판매금액의 %d %% 가 세금으로 나가게됩니다"), iVal);
  390.  
  391. CMonarch::instance().SendtoDBAddMoney(dwTax, m_pkPC->GetEmpire(), m_pkPC);
  392. }
  393. else
  394. {
  395. if (item->IsDragonSoul())
  396. item->AddToCharacter(ch, TItemPos(DRAGON_SOUL_INVENTORY, iEmptyPos));
  397. else
  398. item->AddToCharacter(ch, TItemPos(INVENTORY, iEmptyPos));
  399. ITEM_MANAGER::instance().FlushDelayedSave(item);
  400. LogManager::instance().ItemLog(ch, item, "BUY", item->GetName());
  401.  
  402. if (item->GetVnum() >= 80003 && item->GetVnum() <= 80007)
  403. {
  404. LogManager::instance().GoldBarLog(ch->GetPlayerID(), item->GetID(), PERSONAL_SHOP_BUY, "");
  405. }
  406.  
  407. DBManager::instance().SendMoneyLog(MONEY_LOG_SHOP, item->GetVnum(), -dwPrice);
  408. }
  409.  
  410. if (item)
  411. sys_log(0, "SHOP: BUY: name %s %s(x %d):%u price %u", ch->GetName(), item->GetName(), item->GetCount(), item->GetID(), dwPrice);
  412.  
  413. ch->Save();
  414.  
  415. return (SHOP_SUBHEADER_GC_OK);
  416. }
  417.  
  418. bool CShop::AddGuest(LPCHARACTER ch, DWORD owner_vid, bool bOtherEmpire)
  419. {
  420. if (!ch)
  421. return false;
  422.  
  423. if (ch->GetExchange())
  424. return false;
  425.  
  426. if (ch->GetShop())
  427. return false;
  428.  
  429. ch->SetShop(this);
  430.  
  431. m_map_guest.insert(GuestMapType::value_type(ch, bOtherEmpire));
  432.  
  433. TPacketGCShop pack;
  434.  
  435. pack.header = HEADER_GC_SHOP;
  436. pack.subheader = SHOP_SUBHEADER_GC_START;
  437.  
  438. TPacketGCShopStart pack2;
  439.  
  440. memset(&pack2, 0, sizeof(pack2));
  441. pack2.owner_vid = owner_vid;
  442.  
  443. for (DWORD i = 0; i < m_itemVector.size() && i < SHOP_HOST_ITEM_MAX_NUM; ++i)
  444. {
  445. const SHOP_ITEM & item = m_itemVector[i];
  446.  
  447. //HIVALUE_ITEM_EVENT
  448. if (quest::CQuestManager::instance().GetEventFlag("hivalue_item_sell") == 0)
  449. {
  450. //축복의 구슬 && 만년한철 이벤트
  451. if (item.vnum == 70024 || item.vnum == 70035)
  452. {
  453. continue;
  454. }
  455. }
  456. //END_HIVALUE_ITEM_EVENT
  457. if (m_pkPC && !item.pkItem)
  458. continue;
  459.  
  460. pack2.items[i].vnum = item.vnum;
  461.  
  462. if (bOtherEmpire) // no empire price penalty for pc shop
  463. pack2.items[i].price = item.price * 3;
  464. else
  465. pack2.items[i].price = item.price;
  466.  
  467. pack2.items[i].count = item.count;
  468.  
  469. if (item.pkItem)
  470. {
  471. thecore_memcpy(pack2.items[i].alSockets, item.pkItem->GetSockets(), sizeof(pack2.items[i].alSockets));
  472. thecore_memcpy(pack2.items[i].aAttr, item.pkItem->GetAttributes(), sizeof(pack2.items[i].aAttr));
  473. }
  474. }
  475.  
  476. pack.size = sizeof(pack) + sizeof(pack2);
  477.  
  478. ch->GetDesc()->BufferedPacket(&pack, sizeof(TPacketGCShop));
  479. ch->GetDesc()->Packet(&pack2, sizeof(TPacketGCShopStart));
  480. return true;
  481. }
  482.  
  483. void CShop::RemoveGuest(LPCHARACTER ch)
  484. {
  485. if (ch->GetShop() != this)
  486. return;
  487.  
  488. m_map_guest.erase(ch);
  489. ch->SetShop(NULL);
  490.  
  491. TPacketGCShop pack;
  492.  
  493. pack.header = HEADER_GC_SHOP;
  494. pack.subheader = SHOP_SUBHEADER_GC_END;
  495. pack.size = sizeof(TPacketGCShop);
  496.  
  497. ch->GetDesc()->Packet(&pack, sizeof(pack));
  498. }
  499.  
  500. void CShop::Broadcast(const void * data, int bytes)
  501. {
  502. sys_log(1, "Shop::Broadcast %p %d", data, bytes);
  503.  
  504. GuestMapType::iterator it;
  505.  
  506. it = m_map_guest.begin();
  507.  
  508. while (it != m_map_guest.end())
  509. {
  510. LPCHARACTER ch = it->first;
  511.  
  512. if (ch->GetDesc())
  513. ch->GetDesc()->Packet(data, bytes);
  514.  
  515. ++it;
  516. }
  517. }
  518.  
  519. void CShop::BroadcastUpdateItem(BYTE pos)
  520. {
  521. TPacketGCShop pack;
  522. TPacketGCShopUpdateItem pack2;
  523.  
  524. TEMP_BUFFER buf;
  525.  
  526. pack.header = HEADER_GC_SHOP;
  527. pack.subheader = SHOP_SUBHEADER_GC_UPDATE_ITEM;
  528. pack.size = sizeof(pack) + sizeof(pack2);
  529.  
  530. pack2.pos = pos;
  531.  
  532. if (m_pkPC && !m_itemVector[pos].pkItem)
  533. pack2.item.vnum = 0;
  534. else
  535. {
  536. pack2.item.vnum = m_itemVector[pos].vnum;
  537. if (m_itemVector[pos].pkItem)
  538. {
  539. thecore_memcpy(pack2.item.alSockets, m_itemVector[pos].pkItem->GetSockets(), sizeof(pack2.item.alSockets));
  540. thecore_memcpy(pack2.item.aAttr, m_itemVector[pos].pkItem->GetAttributes(), sizeof(pack2.item.aAttr));
  541. }
  542. else
  543. {
  544. memset(pack2.item.alSockets, 0, sizeof(pack2.item.alSockets));
  545. memset(pack2.item.aAttr, 0, sizeof(pack2.item.aAttr));
  546. }
  547. }
  548.  
  549. pack2.item.price = m_itemVector[pos].price;
  550. pack2.item.count = m_itemVector[pos].count;
  551.  
  552. buf.write(&pack, sizeof(pack));
  553. buf.write(&pack2, sizeof(pack2));
  554.  
  555. Broadcast(buf.read_peek(), buf.size());
  556. }
  557.  
  558. int CShop::GetNumberByVnum(DWORD dwVnum)
  559. {
  560. int itemNumber = 0;
  561.  
  562. for (DWORD i = 0; i < m_itemVector.size() && i < SHOP_HOST_ITEM_MAX_NUM; ++i)
  563. {
  564. const SHOP_ITEM & item = m_itemVector[i];
  565.  
  566. if (item.vnum == dwVnum)
  567. {
  568. itemNumber += item.count;
  569. }
  570. }
  571.  
  572. return itemNumber;
  573. }
  574.  
  575. bool CShop::IsSellingItem(DWORD itemID)
  576. {
  577. bool isSelling = false;
  578.  
  579. for (DWORD i = 0; i < m_itemVector.size() && i < SHOP_HOST_ITEM_MAX_NUM; ++i)
  580. {
  581. if ((unsigned int)(m_itemVector[i].itemid) == itemID)
  582. {
  583. isSelling = true;
  584. break;
  585. }
  586. }
  587.  
  588. return isSelling;
  589.  
  590. }
Advertisement
Add Comment
Please, Sign In to add comment