Advertisement
Guest User

Shop_manager

a guest
Feb 20th, 2020
170
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 29.22 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 "offline_shop.h"
  8. #include "desc.h"
  9. #include "desc_manager.h"
  10. #include "char.h"
  11. #include "char_manager.h"
  12. #include "item.h"
  13. #include "item_manager.h"
  14. #include "buffer_manager.h"
  15. #include "packet.h"
  16. #include "log.h"
  17. #include "db.h"
  18. #include "questmanager.h"
  19. #include "monarch.h"
  20. #include "mob_manager.h"
  21. #include "locale_service.h"
  22. #include "desc_client.h"
  23. #include "shop_manager.h"
  24. #include "group_text_parse_tree.h"
  25. #include "shopEx.h"
  26. #include <boost/algorithm/string/predicate.hpp>
  27. #include "shop_manager.h"
  28. #include "input.h"
  29. #include "p2p.h"
  30. #include <cctype>
  31.  
  32. CShopManager::CShopManager()
  33. {
  34. }
  35.  
  36. CShopManager::~CShopManager()
  37. {
  38.     Destroy();
  39. }
  40.  
  41. bool CShopManager::Initialize(TShopTable * table, int size)
  42. {
  43.     if (!m_map_pkShop.empty())
  44.         return false;
  45.  
  46.     int i;
  47.  
  48.     for (i = 0; i < size; ++i, ++table)
  49.     {
  50.         LPSHOP shop = M2_NEW CShop;
  51.  
  52.         if (!shop->Create(table->dwVnum, table->dwNPCVnum, table->items))
  53.         {
  54.             M2_DELETE(shop);
  55.             continue;
  56.         }
  57.  
  58.         m_map_pkShop.insert(TShopMap::value_type(table->dwVnum, shop));
  59.         m_map_pkShopByNPCVnum.insert(TShopMap::value_type(table->dwNPCVnum, shop));
  60.     }
  61.     char szShopTableExFileName[256];
  62.  
  63.     snprintf(szShopTableExFileName, sizeof(szShopTableExFileName),
  64.         "%s/shop_table_ex.txt", LocaleService_GetBasePath().c_str());
  65.  
  66.     return ReadShopTableEx(szShopTableExFileName);
  67. }
  68.  
  69. void CShopManager::Destroy()
  70. {
  71.     TShopMap::iterator it = m_map_pkShop.begin();
  72.  
  73.     while (it != m_map_pkShop.end())
  74.     {
  75.         M2_DELETE(it->second);
  76.         ++it;
  77.     }
  78.  
  79.     m_map_pkShop.clear();
  80.  
  81.     TOfflineShopMap::iterator offIt = m_map_pkOfflineShopByPC.begin();
  82.    
  83.     while (offIt != m_map_pkOfflineShopByPC.end()){
  84.         M2_DELETE(offIt->second);
  85.         ++offIt;
  86.     }
  87.  
  88.     m_map_pkOfflineShopByPC.clear();
  89. }
  90.  
  91. LPSHOP CShopManager::Get(DWORD dwVnum)
  92. {
  93.     TShopMap::const_iterator it = m_map_pkShop.find(dwVnum);
  94.  
  95.     if (it == m_map_pkShop.end())
  96.         return NULL;
  97.  
  98.     return (it->second);
  99. }
  100.  
  101. LPSHOP CShopManager::GetByNPCVnum(DWORD dwVnum)
  102. {
  103.     TShopMap::const_iterator it = m_map_pkShopByNPCVnum.find(dwVnum);
  104.  
  105.     if (it == m_map_pkShopByNPCVnum.end())
  106.         return NULL;
  107.  
  108.     return (it->second);
  109. }
  110.  
  111. /*
  112.  * 인터페이스 함수들
  113.  */
  114.  
  115. // 상점 거래를 시작
  116. bool CShopManager::StartShopping(LPCHARACTER pkChr, LPCHARACTER pkChrShopKeeper, int iShopVnum)
  117. {
  118.     if (pkChr->GetShopOwner() == pkChrShopKeeper)
  119.         return false;
  120.    
  121.     if (pkChr->GetOfflineShop())
  122.         return false;
  123.    
  124.     // this method is only for NPC
  125.     if (pkChrShopKeeper->IsPC())
  126.         return false;
  127.  
  128.     //PREVENT_TRADE_WINDOW
  129.     if (pkChr->IsOpenSafebox() || pkChr->GetExchange() || pkChr->GetMyShop() || pkChr->IsCubeOpen() || pkChr->IsInventoryLocked())
  130.     {
  131.         pkChr->ChatPacket(CHAT_TYPE_INFO, "Non e' possibile acquistare in questo negozio ");
  132.         return false;
  133.     }
  134.     //END_PREVENT_TRADE_WINDOW
  135.  
  136.     long distance = DISTANCE_APPROX(pkChr->GetX() - pkChrShopKeeper->GetX(), pkChr->GetY() - pkChrShopKeeper->GetY());
  137.  
  138.     if (distance >= SHOP_MAX_DISTANCE)
  139.     {
  140.         sys_log(1, "SHOP: TOO_FAR: %s distance %d", pkChr->GetName(), distance);
  141.         return false;
  142.     }
  143.  
  144.     LPSHOP pkShop;
  145.  
  146.     if (iShopVnum)
  147.         pkShop = Get(iShopVnum);
  148.     else
  149.         pkShop = GetByNPCVnum(pkChrShopKeeper->GetRaceNum());
  150.  
  151.     if (!pkShop)
  152.     {
  153.         sys_log(1, "SHOP: NO SHOP");
  154.         return false;
  155.     }
  156.  
  157.     bool bOtherEmpire = false;
  158.  
  159.     if (pkChr->GetEmpire() != pkChrShopKeeper->GetEmpire())
  160.         bOtherEmpire = true;
  161.  
  162.     pkShop->AddGuest(pkChr, pkChrShopKeeper->GetVID(), bOtherEmpire);
  163.     pkChr->SetShopOwner(pkChrShopKeeper);
  164.     sys_log(0, "SHOP: START: %s", pkChr->GetName());
  165.     return true;
  166. }
  167.  
  168. LPSHOP CShopManager::FindPCShop(DWORD dwVID)
  169. {
  170.     TShopMap::iterator it = m_map_pkShopByPC.find(dwVID);
  171.  
  172.     if (it == m_map_pkShopByPC.end())
  173.         return NULL;
  174.  
  175.     return it->second;
  176. }
  177.  
  178. LPSHOP CShopManager::CreatePCShop(LPCHARACTER ch, TShopItemTable * pTable, BYTE bItemCount)
  179. {
  180.     if (FindPCShop(ch->GetVID()))
  181.         return NULL;
  182.  
  183.     LPSHOP pkShop = M2_NEW CShop;
  184.     pkShop->SetPCShop(ch);
  185.     pkShop->SetShopItems(pTable, bItemCount);
  186.  
  187.     m_map_pkShopByPC.insert(TShopMap::value_type(ch->GetVID(), pkShop));
  188.     return pkShop;
  189. }
  190.  
  191. void CShopManager::DestroyPCShop(LPCHARACTER ch)
  192. {
  193.     LPSHOP pkShop = FindPCShop(ch->GetVID());
  194.  
  195.     if (!pkShop)
  196.         return;
  197.  
  198.     //PREVENT_ITEM_COPY;
  199.     ch->SetMyShopTime();
  200.     //END_PREVENT_ITEM_COPY
  201.    
  202.     m_map_pkShopByPC.erase(ch->GetVID());
  203.     M2_DELETE(pkShop);
  204. }
  205.  
  206. // 상점 거래를 종료
  207. void CShopManager::StopShopping(LPCHARACTER ch)
  208. {
  209.     LPOFFLINESHOP offShop = ch->GetOfflineShop();
  210.     if (offShop){
  211.         ch->SetMyShopTime();
  212.         offShop->RemoveGuest(ch);
  213.         sys_log(0, "OFFLINE SHOP: END: %s", ch->GetName());
  214.         return;
  215.     }
  216.  
  217.     LPSHOP shop;
  218.  
  219.     if (!(shop = ch->GetShop()))
  220.         return;
  221.  
  222.     //PREVENT_ITEM_COPY;
  223.     ch->SetMyShopTime();
  224.     //END_PREVENT_ITEM_COPY
  225.    
  226.     shop->RemoveGuest(ch);
  227.     sys_log(0, "SHOP: END: %s", ch->GetName());
  228. }
  229.  
  230. // 아이템 구입
  231. void CShopManager::Buy(LPCHARACTER ch, BYTE pos){
  232.     if (ch->IsInventoryLocked()){
  233.         ch->ChatPacket(CHAT_TYPE_INFO, "Non e' possibile acquistare in questo negozio ");
  234.         return;
  235.     }
  236.  
  237.     //Offline shops system part
  238.     if (ch->GetOfflineShop()){
  239.         COfflineShop* pkOfflineShop = ch->GetOfflineShop();
  240.         if (!pkOfflineShop)
  241.             return;
  242.  
  243.         if (DISTANCE_APPROX(ch->GetX() - ch->GetShopOwner()->GetX(), ch->GetY() - ch->GetShopOwner()->GetY()) > 2000){
  244.             ch->ChatPacket(CHAT_TYPE_INFO, "Sei troppo lontano dal negozio");
  245.             return;
  246.         }
  247.  
  248.         //PREVENT_ITEM_COPY
  249.         ch->SetMyShopTime();
  250.         //END_PREVENT_ITEM_COPY
  251.  
  252.         int ret = pkOfflineShop->Buy(ch, pos);
  253.  
  254.         if (SHOP_SUBHEADER_GC_OK != ret){
  255.             TPacketGCShop pack;
  256.  
  257.             pack.header = HEADER_GC_SHOP;
  258.             pack.subheader  = ret;
  259.             pack.size   = sizeof(TPacketGCShop);
  260.  
  261.             ch->GetDesc()->Packet(&pack, sizeof(pack));
  262.         }
  263.         return;
  264.     }
  265.  
  266.     if (!ch->GetShop())
  267.         return;
  268.  
  269.     if (!ch->GetShopOwner())
  270.         return;
  271.  
  272.     if (DISTANCE_APPROX(ch->GetX() - ch->GetShopOwner()->GetX(), ch->GetY() - ch->GetShopOwner()->GetY()) > 2000)
  273.     {
  274.         ch->ChatPacket(CHAT_TYPE_INFO, "Sei troppo lontano dal negozio");
  275.         return;
  276.     }
  277.  
  278.     CShop* pkShop = ch->GetShop();
  279.  
  280.     if (!pkShop->IsPCShop())
  281.     {
  282.         //if (pkShop->GetVnum() == 0)
  283.         //  return;
  284.         //const CMob* pkMob = CMobManager::instance().Get(pkShop->GetNPCVnum());
  285.         //if (!pkMob)
  286.         //  return;
  287.  
  288.         //if (pkMob->m_table.bType != CHAR_TYPE_NPC)
  289.         //{
  290.         //  return;
  291.         //}
  292.     }
  293.     else
  294.     {
  295.     }
  296.  
  297.     //PREVENT_ITEM_COPY
  298.     ch->SetMyShopTime();
  299.     //END_PREVENT_ITEM_COPY
  300.  
  301.     int ret = pkShop->Buy(ch, pos);
  302.  
  303.     if (SHOP_SUBHEADER_GC_OK != ret) // 문제가 있었으면 보낸다.
  304.     {
  305.         TPacketGCShop pack;
  306.  
  307.         pack.header = HEADER_GC_SHOP;
  308.         pack.subheader  = ret;
  309.         pack.size   = sizeof(TPacketGCShop);
  310.  
  311.         ch->GetDesc()->Packet(&pack, sizeof(pack));
  312.     }
  313. }
  314.  
  315. void CShopManager::Sell(LPCHARACTER ch, BYTE bCell, BYTE bCount)
  316. {
  317.     if (!ch->GetShop())
  318.         return;
  319.  
  320.     if (!ch->GetShopOwner())
  321.         return;
  322.  
  323.     if (!ch->CanHandleItem())
  324.         return;
  325.  
  326.     if (ch->GetShop()->IsPCShop())
  327.         return;
  328.  
  329.     if (DISTANCE_APPROX(ch->GetX()-ch->GetShopOwner()->GetX(), ch->GetY()-ch->GetShopOwner()->GetY())>2000)
  330.     {
  331.         ch->ChatPacket(CHAT_TYPE_INFO, "Sei troppo lontano per vedere il negozio");
  332.         return;
  333.     }
  334.    
  335.     LPITEM item = ch->GetInventoryItem(bCell);
  336.  
  337.     if (!item)
  338.         return;
  339.  
  340.     if (item->IsEquipped() == true)
  341.     {
  342.         ch->ChatPacket(CHAT_TYPE_INFO, "Non puoi vendere oggetti equipaggiati");
  343.         return;
  344.     }
  345.  
  346.     if (true == item->isLocked())
  347.     {
  348.         ch->ChatPacket(CHAT_TYPE_INFO, "Non puoi vendere un oggetto con l'inventario bloccato.");
  349.         return;
  350.     }
  351.  
  352.     if (IS_SET(item->GetAntiFlag(), ITEM_ANTIFLAG_SELL))
  353.         return;
  354.  
  355. #ifdef _PREMIUM_INVENTORY_ENABLED_
  356.     TItemPos item_pos(INVENTORY, item->GetCell());
  357.     if (item_pos.IsPremiumInventoryPosition() && ch->GetPremiumRemainSeconds(PREMIUM_INVENTORY) <= 0)
  358.     {
  359.         ch->ChatPacket(CHAT_TYPE_INFO, "Devi acquistare l'inventario premium per utilizzare questa pagina");
  360.         return;
  361.     }
  362. #endif
  363.  
  364.     DWORD dwPrice;
  365.  
  366.     if (bCount == 0 || bCount > item->GetCount())
  367.         bCount = item->GetCount();
  368.  
  369.     dwPrice = item->GetShopBuyPrice();
  370.  
  371.     if (IS_SET(item->GetFlag(), ITEM_FLAG_COUNT_PER_1GOLD))
  372.     {
  373.         if (dwPrice == 0)
  374.             dwPrice = bCount;
  375.         else
  376.             dwPrice = bCount / dwPrice;
  377.     }
  378.     else
  379.         dwPrice *= bCount;
  380.  
  381.     dwPrice /= 5;
  382.    
  383.     //세금 계산
  384.     DWORD dwTax = 0;
  385.     int iVal = 3;
  386.    
  387.     if (LC_IsYMIR() ||  LC_IsKorea())
  388.     {
  389.         dwTax = dwPrice * iVal / 100;
  390.         dwPrice -= dwTax;
  391.     }
  392.     else
  393.     {
  394.         dwTax = dwPrice * iVal/100;
  395.         dwPrice -= dwTax;
  396.     }
  397.  
  398.     if (test_server)
  399.         sys_log(0, "Sell Item price id %d %s itemid %d", ch->GetPlayerID(), ch->GetName(), item->GetID());
  400.  
  401.     const int64_t nTotalMoney = static_cast<int64_t>(ch->GetGold()) + static_cast<int64_t>(dwPrice);
  402.  
  403.     if (GOLD_MAX <= nTotalMoney)
  404.     {
  405.         sys_err("[OVERFLOW_GOLD] id %u name %s gold %u", ch->GetPlayerID(), ch->GetName(), ch->GetGold());
  406.         ch->ChatPacket(CHAT_TYPE_INFO, "Non puoi avere pi?di 999 miliardi di yang");
  407.         return;
  408.     }
  409.  
  410.     // 20050802.myevan.상점 판매 로그에 아이템 ID 추가
  411.     sys_log(0, "SHOP: SELL: %s item name: %s(x%d):%u price: %u", ch->GetName(), item->GetName(), bCount, item->GetID(), dwPrice);
  412.  
  413.     if (iVal > 0)
  414.         ch->ChatPacket(CHAT_TYPE_INFO, "La vendita e' tassata di %d%%", iVal);
  415.  
  416.     DBManager::instance().SendMoneyLog(MONEY_LOG_SHOP, item->GetVnum(), dwPrice);
  417.  
  418.     if (bCount == item->GetCount())
  419.     {
  420.         // 한국에는 아이템을 버리고 복구해달라는 진상유저들이 많아서
  421.         // 상점 판매시 속성로그를 남긴다.
  422.         if (LC_IsYMIR())
  423.             item->AttrLog();
  424.  
  425.         ITEM_MANAGER::instance().RemoveItem(item, "SELL");
  426.     }
  427.     else
  428.         item->SetCount(item->GetCount() - bCount);
  429.  
  430.     //군주 시스템 : 세금 징수
  431.     CMonarch::instance().SendtoDBAddMoney(dwTax, ch->GetEmpire(), ch);
  432.  
  433.     ch->PointChange(POINT_GOLD, dwPrice, false);
  434. }
  435.  
  436. bool CompareShopItemName(const SShopItemTable& lhs, const SShopItemTable& rhs)
  437. {
  438.     TItemTable* lItem = ITEM_MANAGER::instance().GetTable(lhs.vnum);
  439.     TItemTable* rItem = ITEM_MANAGER::instance().GetTable(rhs.vnum);
  440.     if (lItem && rItem)
  441.         return strcmp(lItem->szLocaleName, rItem->szLocaleName) < 0;
  442.     else
  443.         return true;
  444. }
  445.  
  446. bool ConvertToShopItemTable(IN CGroupNode* pNode, OUT TShopTableEx& shopTable)
  447. {
  448.     if (!pNode->GetValue("vnum", 0, shopTable.dwVnum))
  449.     {
  450.         sys_err("Group %s does not have vnum.", pNode->GetNodeName().c_str());
  451.         return false;
  452.     }
  453.  
  454.     if (!pNode->GetValue("name", 0, shopTable.name))
  455.     {
  456.         sys_err("Group %s does not have name.", pNode->GetNodeName().c_str());
  457.         return false;
  458.     }
  459.    
  460.     if (shopTable.name.length() >= SHOP_TAB_NAME_MAX)
  461.     {
  462.         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());
  463.         return false;
  464.     }
  465.  
  466.     std::string stCoinType;
  467.     if (!pNode->GetValue("cointype", 0, stCoinType))
  468.     {
  469.         stCoinType = "Gold";
  470.     }
  471.    
  472.     if (boost::iequals(stCoinType, "Gold"))
  473.     {
  474.         shopTable.coinType = SHOP_COIN_TYPE_GOLD;
  475.     }
  476.     else if (boost::iequals(stCoinType, "SecondaryCoin"))
  477.     {
  478.         shopTable.coinType = SHOP_COIN_TYPE_SECONDARY_COIN;
  479.     }
  480.     else
  481.     {
  482.         sys_err("Group %s has undefine cointype(%s).", pNode->GetNodeName().c_str(), stCoinType.c_str());
  483.         return false;
  484.     }
  485.  
  486.     CGroupNode* pItemGroup = pNode->GetChildNode("items");
  487.     if (!pItemGroup)
  488.     {
  489.         sys_err("Group %s does not have 'group items'.", pNode->GetNodeName().c_str());
  490.         return false;
  491.     }
  492.  
  493.     int itemGroupSize = pItemGroup->GetRowCount();
  494.     std::vector <TShopItemTable> shopItems(itemGroupSize);
  495.     if (itemGroupSize >= SHOP_HOST_ITEM_MAX_NUM)
  496.     {
  497.         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);
  498.         return false;
  499.     }
  500.  
  501.     for (int i = 0; i < itemGroupSize; i++)
  502.     {
  503.         if (!pItemGroup->GetValue(i, "vnum", shopItems[i].vnum))
  504.         {
  505.             sys_err("row(%d) of group items of group %s does not have vnum column", i, pNode->GetNodeName().c_str());
  506.             return false;
  507.         }
  508.        
  509.         if (!pItemGroup->GetValue(i, "count", shopItems[i].count))
  510.         {
  511.             sys_err("row(%d) of group items of group %s does not have count column", i, pNode->GetNodeName().c_str());
  512.             return false;
  513.         }
  514.  
  515.         shopItems[i].price.price = 0;
  516.         pItemGroup->GetValue(i, "rep", shopItems[i].price.reputationPoints);
  517.         if (!pItemGroup->GetValue(i, "price", shopItems[i].price.price) && !shopItems[i].price.reputationPoints){
  518.             sys_err("row(%d) of group items of group %s does not have price column", i, pNode->GetNodeName().c_str());
  519.             return false;
  520.         }
  521.     }
  522.     std::string stSort;
  523.     if (!pNode->GetValue("sort", 0, stSort))
  524.     {
  525.         stSort = "None";
  526.     }
  527.  
  528.     if (boost::iequals(stSort, "Asc"))
  529.     {
  530.         std::sort(shopItems.begin(), shopItems.end(), CompareShopItemName);
  531.     }
  532.     else if(boost::iequals(stSort, "Desc"))
  533.     {
  534.         std::sort(shopItems.rbegin(), shopItems.rend(), CompareShopItemName);
  535.     }
  536.  
  537.     CGrid grid = CGrid(5, 9);
  538.     int iPos;
  539.  
  540.     memset(&shopTable.items[0], 0, sizeof(shopTable.items));
  541.  
  542.     for (int i = 0; i < shopItems.size(); i++)
  543.     {
  544.         TItemTable * item_table = ITEM_MANAGER::instance().GetTable(shopItems[i].vnum);
  545.         if (!item_table)
  546.         {
  547.             sys_err("vnum(%d) of group items of group %s does not exist", shopItems[i].vnum, pNode->GetNodeName().c_str());
  548.             return false;
  549.         }
  550.  
  551.         iPos = grid.FindBlank(1, item_table->bSize);
  552.  
  553.         grid.Put(iPos, 1, item_table->bSize);
  554.         shopTable.items[iPos] = shopItems[i];
  555.     }
  556.  
  557.     shopTable.byItemCount = shopItems.size();
  558.     return true;
  559. }
  560.  
  561. bool CShopManager::ReadShopTableEx(const char* stFileName)
  562. {
  563.     // file 유무 체크.
  564.     // 없는 경우는 에러로 처리하지 않는다.
  565.     FILE* fp = fopen(stFileName, "rb");
  566.     if (NULL == fp)
  567.         return true;
  568.     fclose(fp);
  569.  
  570.     CGroupTextParseTreeLoader loader;
  571.     if (!loader.Load(stFileName))
  572.     {
  573.         sys_err("%s Load fail.", stFileName);
  574.         return false;
  575.     }
  576.  
  577.     CGroupNode* pShopNPCGroup = loader.GetGroup("shopnpc");
  578.     if (NULL == pShopNPCGroup)
  579.     {
  580.         sys_err("Group ShopNPC is not exist.");
  581.         return false;
  582.     }
  583.  
  584.     typedef std::multimap <DWORD, TShopTableEx> TMapNPCshop;
  585.     TMapNPCshop map_npcShop;
  586.     for (int i = 0; i < pShopNPCGroup->GetRowCount(); i++)
  587.     {
  588.         DWORD npcVnum;
  589.         std::string shopName;
  590.         if (!pShopNPCGroup->GetValue(i, "npc", npcVnum) || !pShopNPCGroup->GetValue(i, "group", shopName))
  591.         {
  592.             sys_err("Invalid row(%d). Group ShopNPC rows must have 'npc', 'group' columns", i);
  593.             return false;
  594.         }
  595.         std::transform(shopName.begin(), shopName.end(), shopName.begin(), (int(*)(int))std::tolower);
  596.         CGroupNode* pShopGroup = loader.GetGroup(shopName.c_str());
  597.         if (!pShopGroup)
  598.         {
  599.             sys_err("Group %s is not exist.", shopName.c_str());
  600.             return false;
  601.         }
  602.         TShopTableEx table;
  603.         if (!ConvertToShopItemTable(pShopGroup, table))
  604.         {
  605.             sys_err("Cannot read Group %s.", shopName.c_str());
  606.             return false;
  607.         }
  608.         if (m_map_pkShopByNPCVnum.find(npcVnum) != m_map_pkShopByNPCVnum.end())
  609.         {
  610.             sys_err("%d cannot have both original shop and extended shop", npcVnum);
  611.             return false;
  612.         }
  613.        
  614.         map_npcShop.insert(TMapNPCshop::value_type(npcVnum, table));   
  615.     }
  616.  
  617.     for (TMapNPCshop::iterator it = map_npcShop.begin(); it != map_npcShop.end(); ++it)
  618.     {
  619.         DWORD npcVnum = it->first;
  620.         TShopTableEx& table = it->second;
  621.         if (m_map_pkShop.find(table.dwVnum) != m_map_pkShop.end())
  622.         {
  623.             sys_err("Shop vnum(%d) already exists", table.dwVnum);
  624.             return false;
  625.         }
  626.         TShopMap::iterator shop_it = m_map_pkShopByNPCVnum.find(npcVnum);
  627.        
  628.         LPSHOPEX pkShopEx = NULL;
  629.         if (m_map_pkShopByNPCVnum.end() == shop_it)
  630.         {
  631.             pkShopEx = M2_NEW CShopEx;
  632.             pkShopEx->Create(0, npcVnum);
  633.             m_map_pkShopByNPCVnum.insert(TShopMap::value_type(npcVnum, pkShopEx));
  634.         }
  635.         else
  636.         {
  637.             pkShopEx = dynamic_cast <CShopEx*> (shop_it->second);
  638.             if (NULL == pkShopEx)
  639.             {
  640.                 sys_err("WTF!!! It can't be happend. NPC(%d) Shop is not extended version.", shop_it->first);
  641.                 return false;
  642.             }
  643.         }
  644.  
  645.         if (pkShopEx->GetTabCount() >= SHOP_TAB_COUNT_MAX)
  646.         {
  647.             sys_err("ShopEx cannot have tab more than %d", SHOP_TAB_COUNT_MAX);
  648.             return false;
  649.         }
  650.  
  651.         if (pkShopEx->GetVnum() != 0 && m_map_pkShop.find(pkShopEx->GetVnum()) != m_map_pkShop.end())
  652.         {
  653.             sys_err("Shop vnum(%d) already exist.", pkShopEx->GetVnum());
  654.             return false;
  655.         }
  656.         m_map_pkShop.insert(TShopMap::value_type (pkShopEx->GetVnum(), pkShopEx));
  657.         pkShopEx->AddShopTable(table);
  658.     }
  659.  
  660.     return true;
  661. }
  662.  
  663. bool CShopManager::LoadOfflineShop(){
  664.     sys_log(0, "Loading offline shops");
  665.  
  666.     const char * query = "SELECT `owner_pid`, `shop_name`, UNIX_TIMESTAMP(ADDDATE(`start_time`, INTERVAL `shop_duration` SECOND)), `x`, `y`, `map_index`, `channel`, `gold`, `millions`, `billions`, `owner_name`, `owner_aid`, `time_type`, `shop_duration` FROM `player_shop_proto`;";
  667.     SQLMsg* sqlMsg = DBManager::instance().DirectQuery(query);
  668.      
  669.     MYSQL_RES* pRes = sqlMsg->vec_pkResult[0]->pSQLResult;
  670.      
  671.     if (sizeof(pRes) <= 1){
  672.         sys_err("Problema nel leggere la tabella shop!");
  673.         return false;
  674.     }
  675.  
  676.     while (MYSQL_ROW data = mysql_fetch_row(pRes)){
  677.         DWORD ownerPID = 0, ownerAID = 0;
  678.         int timeType = 0, shopDuration = 0;
  679.         str_to_number(ownerPID, data[0]);
  680.         str_to_number(ownerAID, data[11]);
  681.         str_to_number(timeType, data[12]);
  682.         str_to_number(shopDuration, data[13]);
  683.        
  684.         if (!shopDuration){
  685.             continue;
  686.         }
  687.        
  688.         int iChannel = 0;
  689.         long lMapIndex = 0;
  690.         str_to_number(lMapIndex, data[5]);
  691.         str_to_number(iChannel, data[6]);
  692.        
  693.         if (g_bChannel != iChannel || !map_allow_find(lMapIndex)){
  694.             continue;
  695.         }
  696.  
  697.         DWORD dw_shopCloseTime = 0;
  698.         str_to_number(dw_shopCloseTime, data[2]);
  699.        
  700.         sys_log(0, "-> ShopCloseTime: %u, Current time %u, duration %i", dw_shopCloseTime, get_global_time(), timeType);
  701.  
  702.         if (timeType != 4 && dw_shopCloseTime <= get_global_time()){
  703.             DBManager::instance().DirectQuery("UPDATE `player`.`player_shop_proto` SET `shop_duration`=0 WHERE `owner_pid`='%u';", ownerPID);
  704.             LogManager::instance().OfflineShopLog(ownerPID, "BOOT_CLOSE", "NO_MORE_TIME");
  705.             continue;
  706.         }
  707.  
  708.         BYTE bItemCount = 0;
  709.  
  710.         char szQuery[QUERY_MAX_LEN];
  711.         snprintf(szQuery, sizeof(szQuery), "SELECT * FROM player_shop_items WHERE owner_id = '%u' AND sold = 0;", ownerPID);
  712.  
  713.         std::auto_ptr<SQLMsg> msg(DBManager::instance().DirectQuery(szQuery));
  714.  
  715.         if (!msg->Get()->uiNumRows){
  716.             DBManager::instance().DirectQuery("UPDATE `player`.`player_shop_proto` SET `shop_duration`=0 WHERE `owner_pid`='%u';", ownerPID);
  717.             LogManager::instance().OfflineShopLog(ownerPID, "BOOT_CLOSE", "NO_MORE_ITEMS");
  718.             continue;
  719.         }
  720.  
  721.         TShopItemTable * itemTable = new TShopItemTable[msg->Get()->uiNumRows*sizeof(TShopItemTable)];
  722.         TAdditionalShopItemTable * itemExtraTable = new TAdditionalShopItemTable[msg->Get()->uiNumRows*sizeof(TAdditionalShopItemTable)];
  723.        
  724.         while (MYSQL_ROW itemRow = mysql_fetch_row(msg->Get()->pSQLResult)){
  725.             TShopItemTable tempItemTable;
  726.             TAdditionalShopItemTable tempExtraItemTable;
  727.             TItemPrice tmpItemPrice;
  728.             memset(&tempItemTable, 0, sizeof(TShopItemTable));
  729.        
  730.             int gold = 0, millions = 0, billions  = 0;
  731.             str_to_number(tempExtraItemTable.id, itemRow[1]);   //Moved to tempExtraItemTable
  732.             str_to_number(tempItemTable.vnum, itemRow[2]);
  733.             str_to_number(tempItemTable.count, itemRow[3]);
  734.             str_to_number(tempItemTable.display_pos, itemRow[4]);
  735.    
  736.             str_to_number(gold, itemRow[5]);
  737.             str_to_number(millions, itemRow[6]);
  738.             str_to_number(billions, itemRow[7]);
  739.    
  740.             tmpItemPrice.price = gold;
  741.             tmpItemPrice.millionBills = millions;
  742.             tmpItemPrice.billionBills = billions;
  743.            
  744.             tempItemTable.price = tmpItemPrice;
  745.            
  746.             int cur = 9;
  747.            
  748.             str_to_number(tempExtraItemTable.alSockets[0], itemRow[cur++]); //Moved to tempExtraItemTable
  749.             str_to_number(tempExtraItemTable.alSockets[1], itemRow[cur++]);
  750.             str_to_number(tempExtraItemTable.alSockets[2], itemRow[cur++]);
  751.  
  752.             for (int j = 0; j < ITEM_ATTRIBUTE_MAX_NUM; j++){                   //Moved to tempExtraItemTable
  753.                 str_to_number(tempExtraItemTable.aAttr[j].bType, itemRow[cur++]);
  754.                 str_to_number(tempExtraItemTable.aAttr[j].sValue, itemRow[cur++]);
  755.             }
  756.            
  757.             itemTable[bItemCount] = tempItemTable;
  758.             itemExtraTable[bItemCount] = tempExtraItemTable;
  759.             bItemCount++;
  760.         }
  761.  
  762.         int xCoord = 0, yCoord = 0;
  763.  
  764.         str_to_number(xCoord, data[3]);
  765.         str_to_number(yCoord, data[4]);
  766.        
  767.         LPCHARACTER pOfflineShop = CHARACTER_MANAGER::instance().SpawnMob(30001, lMapIndex, xCoord, yCoord, 0, false);
  768.  
  769.         if (!pOfflineShop)
  770.             continue;
  771.  
  772.         std::string shopName = "Negozio di ";
  773.         shopName.append(data[10]);
  774.         std::string shopSign = data[1];
  775.  
  776.         pOfflineShop->SetName(shopName);
  777.         pOfflineShop->SetShopCharacter(true);
  778.         pOfflineShop->m_stShopSign = shopSign;
  779.  
  780.         unsigned long gold = 0, millions = 0, billions = 0;
  781.         str_to_number(gold, data[7]);
  782.         str_to_number(millions, data[8]);
  783.         str_to_number(billions, data[9]);
  784.  
  785.         LPOFFLINESHOP m_pkTempShop = CreateOfflinePCShop(ownerPID, itemTable, bItemCount, pOfflineShop->GetVID(), (dw_shopCloseTime - get_global_time()), true, itemExtraTable);
  786.         if (m_pkTempShop){
  787.             m_pkTempShop->AddShopMoney(gold, millions, billions, true);
  788.             m_pkTempShop->SetOfflineShopOwnerAID(ownerAID);
  789.             m_pkTempShop->SetShopTimeType(timeType);
  790.             LogManager::instance().OfflineShopLog(ownerPID, "BOOT_OPEN", shopSign.c_str());
  791.         }
  792.     }
  793.    
  794.     return true;
  795. }
  796.  
  797. LPOFFLINESHOP CShopManager::GetByNPCVID(DWORD dwVID){
  798.     TOfflineShopMap::const_iterator it = m_map_pkOfflineShopByNPCVID.find(dwVID);
  799.  
  800.     if (it == m_map_pkOfflineShopByNPCVID.end())
  801.         return NULL;
  802.  
  803.     return (it->second);
  804. }
  805.  
  806. bool CShopManager::StartOfflineShopping(LPCHARACTER pkChr, LPCHARACTER pkChrShop){
  807.     LPOFFLINESHOP pkShop = GetByNPCVID(pkChrShop->GetVID());
  808.    
  809.     DWORD shopOwnerPID = pkShop->GetOfflineShopOwner();
  810.     LPCHARACTER pChar = CHARACTER_MANAGER::instance().FindByPID(shopOwnerPID);
  811.  
  812.     if (!pkShop){
  813.         sys_log(1, "SHOP: NO OFFLINE SHOP");
  814.         return false;
  815.     }
  816.  
  817.     if (pkChr->IsDead() == true) return false;
  818.  
  819.     //PREVENT_TRADE_WINDOW
  820.     if (pkChr->IsOpenSafebox() || pkChr->GetExchange() || pkChr->GetMyShop() || pkChr->IsCubeOpen() || pkChr->IsInventoryLocked()){
  821.         pkChr->ChatPacket(CHAT_TYPE_INFO, "Non e' possibile acquistare");
  822.         return false;
  823.     }
  824.     //END_PREVENT_TRADE_WINDOW
  825.  
  826.     pkShop->AddGuest(pkChr, pChar ? pChar->GetVID() : 0, false);
  827.     pkChr->SetShopOwner(pkChrShop);
  828.     sys_log(0, "OFFLINESHOP: START: %s", pkChr->GetName());
  829.  
  830.     return true;
  831. }
  832.  
  833. LPOFFLINESHOP CShopManager::CreateOfflinePCShop(DWORD dwOwnerID, TShopItemTable * pTable, BYTE bItemCount, DWORD HostVID, DWORD dwRemainTime, bool isBoot, TAdditionalShopItemTable * itemExtraTable){
  834.     if (FindOfflinePCShopByOwner(dwOwnerID))
  835.         return NULL;
  836.  
  837.     LPOFFLINESHOP pkShop = M2_NEW COfflineShop;
  838.  
  839.     pkShop->SetOfflineShopOwner(dwOwnerID);
  840.     pkShop->SetOfflineShopHost(HostVID);
  841.  
  842.     if (!pkShop->SetShopItems(pTable, bItemCount, isBoot, itemExtraTable)){
  843.         M2_DELETE(pkShop);
  844.         return NULL;
  845.     }
  846.  
  847.     pkShop->SetShopCloseTime(dwRemainTime);
  848.  
  849.     m_map_pkOfflineShopByPC.insert(TOfflineShopMap::value_type(dwOwnerID, pkShop));
  850.     m_map_pkOfflineShopByNPCVID.insert(TOfflineShopMap::value_type(HostVID, pkShop));
  851.    
  852.     StartOfflineShopEvent(pkShop, dwOwnerID);
  853.     SendShopUpdateGGPacket(dwOwnerID, false);
  854.     SyncOfflineShopVector(dwOwnerID, false);
  855.  
  856.     return pkShop;
  857. }
  858.  
  859. void CShopManager::DestroyOfflinePCShop(LPCHARACTER ch)
  860. {
  861.     LPOFFLINESHOP pkShop = FindOfflinePCShopByOwner(ch->GetPlayerID());
  862.  
  863.     if (!pkShop)
  864.         return;
  865.  
  866.     //PREVENT_ITEM_COPY;
  867.     ch->SetMyShopTime();
  868.     //END_PREVENT_ITEM_COPY
  869.  
  870.     CloseOfflinePCShop(pkShop, ch->GetPlayerID());
  871. }
  872.  
  873. void CShopManager::CloseOfflinePCShop(LPOFFLINESHOP pkShop, DWORD dwPID)
  874. {
  875.     EventMap::iterator itFind = m_ShopCloseEventMap.find(dwPID);
  876.  
  877.     if (itFind == m_ShopCloseEventMap.end()){
  878.         sys_err("CloseOfflinePCShop to not exist event PID: %d", dwPID);
  879.         return;
  880.     }
  881.  
  882.     event_cancel(&itFind->second);
  883.     m_ShopCloseEventMap.erase(itFind);
  884.  
  885.     //Destroy the character
  886.     LPCHARACTER pk_Char = CHARACTER_MANAGER::instance().Find(pkShop->GetOfflineShopHost());
  887.  
  888.     if (!pk_Char)
  889.         sys_err("Offline shop error! No shop character to destroy..");
  890.     else
  891.         M2_DESTROY_CHARACTER(pk_Char);
  892.    
  893.     //Update the owner
  894.     LPCHARACTER pk_ownerChar = CHARACTER_MANAGER::instance().FindByPID(pkShop->GetOfflineShopOwner());
  895.  
  896.     if (pk_ownerChar)
  897.         pk_ownerChar->SetMyOfflineShop(NULL);
  898.  
  899.     std::stringstream m_sQuerySS;
  900.     m_sQuerySS << "UPDATE `player_shop_proto` SET `shop_duration`=0 WHERE `owner_pid`='" << dwPID << "';";
  901.     DBManager::instance().Query(m_sQuerySS.str().c_str());
  902.    
  903.     char szHint[100];
  904.     snprintf(szHint, sizeof(szHint), "money %lld %lu %lu", pkShop->m_dwEarnedGold, pkShop->m_dwEarnedMillions, pkShop->m_dwEarnedBillions);
  905.     LogManager::instance().OfflineShopLog(dwPID, "CLOSE", szHint);
  906.  
  907.     m_map_pkOfflineShopByPC.erase(dwPID);
  908.     m_map_pkOfflineShopByNPCVID.erase(pkShop->GetOfflineShopHost());
  909.     SendShopUpdateGGPacket(dwPID, true);
  910.     SyncOfflineShopVector(dwPID, true);
  911.     M2_DELETE(pkShop);
  912. }
  913.  
  914. EVENTINFO(SShopCloseEventInfo)
  915. {
  916.     LPOFFLINESHOP pShop;
  917.     DWORD ownerPID;
  918.  
  919.     SShopCloseEventInfo()
  920.     : pShop(0),
  921.     ownerPID(0)
  922.     {
  923.     }
  924. };
  925.  
  926. EVENTFUNC(close_shop_event){
  927.     SShopCloseEventInfo* info = dynamic_cast<SShopCloseEventInfo*>( event->info );
  928.  
  929.     if (info == NULL){
  930.         sys_err( "close_shop_event> <Factor> Null pointer" );
  931.         return 0;
  932.     }
  933.  
  934.     LPOFFLINESHOP curShop = info->pShop;
  935.     DWORD playerID = info->ownerPID;
  936.  
  937.     if (curShop == NULL || !playerID) {
  938.         sys_err("close_shop_event> wrong PID or shop instance!");
  939.         return 0;
  940.     }
  941.    
  942.     CShopManager::instance().CloseOfflinePCShop(curShop, playerID);
  943. }
  944.  
  945. void CShopManager::StartOfflineShopEvent(LPOFFLINESHOP curShop, DWORD ownerPlayerId){
  946.     if (m_ShopCloseEventMap.end() != m_ShopCloseEventMap.find(ownerPlayerId)){
  947.         sys_err( "close_shop_event> duplicated shop!!! %d", ownerPlayerId);
  948.         return;
  949.     }
  950.  
  951.     SShopCloseEventInfo* info = AllocEventInfo<SShopCloseEventInfo>();
  952.     info->pShop = curShop;
  953.     info->ownerPID = ownerPlayerId;
  954.  
  955.     m_ShopCloseEventMap.insert(EventMap::value_type(ownerPlayerId, event_create(close_shop_event, info, PASSES_PER_SEC(curShop->GetShopCloseTime()))));
  956. }
  957.  
  958. void CShopManager::RefreshShopByID(DWORD dwPlayerID, DWORD dwPremiumRemain){
  959.     EventMap::iterator itFind = m_ShopCloseEventMap.find(dwPlayerID);
  960.  
  961.     if (itFind == m_ShopCloseEventMap.end()){
  962.         sys_err("CloseOfflinePCShop to not exist event PID: %d", dwPlayerID);
  963.         return;
  964.     }
  965.  
  966.    
  967.     LPOFFLINESHOP pkShop = FindOfflinePCShopByOwner(dwPlayerID);
  968.     if (pkShop->GetShopTimeType() != 4)
  969.         return;
  970.  
  971.     event_cancel(&itFind->second);
  972.     m_ShopCloseEventMap.erase(itFind);
  973.    
  974.     pkShop->SetShopCloseTime(dwPremiumRemain);
  975.    
  976.     StartOfflineShopEvent(pkShop, dwPlayerID);
  977. }
  978.  
  979. int CShopManager::CountOfflineShops(){
  980.     return m_map_pkOfflineShopByPC.size();
  981. }
  982.  
  983. int CShopManager::CountGlobalOfflineShops(){
  984.     return m_dvOfflineShopsVector.size();
  985. }
  986.  
  987. void CShopManager::SendShopUpdateGGPacket(DWORD dwPlayerId, bool bRemove){
  988.     TPacketGGShopsUpdate p;
  989.     p.header = HEADER_GG_SHOPS_UPDATE;
  990.     p.dwOwnerID = dwPlayerId;
  991.     p.bRemove = bRemove;
  992.  
  993.     P2P_MANAGER::instance().Send(&p, sizeof(p));
  994.     //sys_log(0, "Sent offline shop update packet, pid %i, remove %i", dwPlayerId, bRemove);
  995. }
  996.  
  997. void CShopManager::SyncOfflineShopVector(DWORD dwPlayerId, bool bRemove){
  998.     //sys_log(0, "Updating offline shop vector, pid %i, remove %i", dwPlayerId, bRemove);
  999.     if (bRemove){
  1000.         std::vector<DWORD>::iterator pos = std::find(m_dvOfflineShopsVector.begin(), m_dvOfflineShopsVector.end(), dwPlayerId);
  1001.         if (pos != m_dvOfflineShopsVector.end())
  1002.             m_dvOfflineShopsVector.erase(pos);
  1003.     }else
  1004.         m_dvOfflineShopsVector.push_back(dwPlayerId);
  1005. }
  1006.  
  1007. LPOFFLINESHOP CShopManager::FindOfflinePCShopByOwner(DWORD dwPID){
  1008.     TOfflineShopMap::iterator it = m_map_pkOfflineShopByPC.find(dwPID);
  1009.  
  1010.     if (it == m_map_pkOfflineShopByPC.end())
  1011.         return NULL;
  1012.  
  1013.     return it->second;
  1014. }
  1015.  
  1016. bool CShopManager::FindOfflinePCShopByAID(DWORD dwAID){
  1017.     TOfflineShopMap::iterator it = m_map_pkOfflineShopByPC.begin();
  1018.  
  1019.     while (it != m_map_pkOfflineShopByPC.end()){
  1020.         LPOFFLINESHOP curShop = it->second;
  1021.         if (curShop->GetOfflineShopOwnerAID() == dwAID)
  1022.             return true;
  1023.         ++it;
  1024.     }
  1025.  
  1026.     return false;
  1027. }
  1028.  
  1029. CShopManager::TOfflineShopMap CShopManager::GetShopMap(){
  1030.     return m_map_pkOfflineShopByPC;
  1031. }
  1032.  
  1033. bool CShopManager::FindOpenedOfflineShop(DWORD dwPlayerId){
  1034.     std::vector<DWORD>::iterator pos = std::find(m_dvOfflineShopsVector.begin(), m_dvOfflineShopsVector.end(), dwPlayerId);
  1035.         if (pos == m_dvOfflineShopsVector.end())
  1036.             if (!CheckOpenedShop(dwPlayerId))
  1037.                 return false;
  1038.     return true;
  1039. }
  1040.  
  1041. bool CShopManager::CheckOpenedShop(DWORD dwPlayerId){
  1042.     //Controllo aggiuntivo per controllare se lo shop e aperto. Se positivo aggiorno anche il vettore globale
  1043.     // visto che se mi trovo che e aperto il core sara sicuramente crashato prima di aggiornare il vettore.
  1044.     //PS: Potrei sostituire anche direttamente il vettore ma e lasciato per comodita e velocita nell esecuzione
  1045.     // rispetto ad una query, un iterazione e ovviamente piu efficiente e veloce.
  1046.     char szQuery[1024+1];
  1047.     std::auto_ptr<SQLMsg> msg;
  1048.  
  1049.     snprintf(szQuery, sizeof(szQuery), "SELECT `owner_pid` FROM player_shop_proto WHERE `owner_pid` = '%u' AND `shop_duration` != 0;", dwPlayerId);
  1050.     msg.reset(DBManager::instance().DirectQuery(szQuery));
  1051.     SQLResult * res = msg->Get();
  1052.    
  1053.     if (res->uiNumRows){
  1054.         //Positivo, quindi ho uno shop aperto in questo od in un altro core ma non ho il vettore del game corrente sincronizzato.
  1055.         //Aggiorno e ritorno true.
  1056.         //sys_err("%u's shop was not inserted into the global vector. Added");
  1057.         SyncOfflineShopVector(dwPlayerId, false);
  1058.         return true;
  1059.     }
  1060.     return false;
  1061. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement