Advertisement
NatedogServer

Allow QS to record STACKED items

Nov 15th, 2014
208
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 8.62 KB | None | 0 0
  1. void Client::Handle_OP_ShopPlayerBuy(const EQApplicationPacket *app)
  2. {
  3.     if (app->size != sizeof(Merchant_Sell_Struct)) {
  4.         LogFile->write(EQEMuLog::Error, "Invalid size on OP_ShopPlayerBuy: Expected %i, Got %i",
  5.             sizeof(Merchant_Sell_Struct), app->size);
  6.         return;
  7.     }
  8.     RDTSC_Timer t1;
  9.     t1.start();
  10.     Merchant_Sell_Struct* mp = (Merchant_Sell_Struct*)app->pBuffer;
  11. #if EQDEBUG >= 5
  12.     LogFile->write(EQEMuLog::Debug, "%s, purchase item..", GetName());
  13.     DumpPacket(app);
  14. #endif
  15.  
  16.     int merchantid;
  17.     bool tmpmer_used = false;
  18.     Mob* tmp = entity_list.GetMob(mp->npcid);
  19.  
  20.     if (tmp == 0 || !tmp->IsNPC() || tmp->GetClass() != MERCHANT)
  21.         return;
  22.  
  23.     if (mp->quantity < 1) return;
  24.  
  25.     //you have to be somewhat close to them to be properly using them
  26.     if (DistNoRoot(*tmp) > USE_NPC_RANGE2)
  27.         return;
  28.  
  29.     merchantid = tmp->CastToNPC()->MerchantType;
  30.  
  31.     uint32 item_id = 0;
  32.     std::list<MerchantList> merlist = zone->merchanttable[merchantid];
  33.     std::list<MerchantList>::const_iterator itr;
  34.     for (itr = merlist.begin(); itr != merlist.end(); ++itr){
  35.         MerchantList ml = *itr;
  36.         if (GetLevel() < ml.level_required) {
  37.             continue;
  38.         }
  39.  
  40.         int32 fac = tmp->GetPrimaryFaction();
  41.         if (fac != 0 && GetModCharacterFactionLevel(fac) < ml.faction_required) {
  42.             continue;
  43.         }
  44.  
  45.         if (mp->itemslot == ml.slot){
  46.             item_id = ml.item;
  47.             break;
  48.         }
  49.     }
  50.     const Item_Struct* item = nullptr;
  51.     uint32 prevcharges = 0;
  52.     if (item_id == 0) { //check to see if its on the temporary table
  53.         std::list<TempMerchantList> tmp_merlist = zone->tmpmerchanttable[tmp->GetNPCTypeID()];
  54.         std::list<TempMerchantList>::const_iterator tmp_itr;
  55.         TempMerchantList ml;
  56.         for (tmp_itr = tmp_merlist.begin(); tmp_itr != tmp_merlist.end(); ++tmp_itr){
  57.             ml = *tmp_itr;
  58.             if (mp->itemslot == ml.slot){
  59.                 item_id = ml.item;
  60.                 tmpmer_used = true;
  61.                 prevcharges = ml.charges;
  62.                 break;
  63.             }
  64.         }
  65.     }
  66.     item = database.GetItem(item_id);
  67.     if (!item){
  68.         //error finding item, client didnt get the update packet for whatever reason, roleplay a tad
  69.         Message(15, "%s tells you 'Sorry, that item is for display purposes only.' as they take the item off the shelf.", tmp->GetCleanName());
  70.         EQApplicationPacket* delitempacket = new EQApplicationPacket(OP_ShopDelItem, sizeof(Merchant_DelItem_Struct));
  71.         Merchant_DelItem_Struct* delitem = (Merchant_DelItem_Struct*)delitempacket->pBuffer;
  72.         delitem->itemslot = mp->itemslot;
  73.         delitem->npcid = mp->npcid;
  74.         delitem->playerid = mp->playerid;
  75.         delitempacket->priority = 6;
  76.         entity_list.QueueCloseClients(tmp, delitempacket); //que for anyone that could be using the merchant so they see the update
  77.         safe_delete(delitempacket);
  78.         return;
  79.     }
  80.     if (CheckLoreConflict(item))
  81.     {
  82.         Message(15, "You can only have one of a lore item.");
  83.         return;
  84.     }
  85.     if (tmpmer_used && (mp->quantity > prevcharges || item->MaxCharges > 1))
  86.     {
  87.         if (prevcharges > item->MaxCharges && item->MaxCharges > 1)
  88.             mp->quantity = item->MaxCharges;
  89.         else
  90.             mp->quantity = prevcharges;
  91.     }
  92.  
  93.     EQApplicationPacket* outapp = new EQApplicationPacket(OP_ShopPlayerBuy, sizeof(Merchant_Sell_Struct));
  94.     Merchant_Sell_Struct* mpo = (Merchant_Sell_Struct*)outapp->pBuffer;
  95.     mpo->quantity = mp->quantity;
  96.     mpo->playerid = mp->playerid;
  97.     mpo->npcid = mp->npcid;
  98.     mpo->itemslot = mp->itemslot;
  99.  
  100.     int16 freeslotid = INVALID_INDEX;
  101.     int16 charges = 0;
  102.     if (item->Stackable || item->MaxCharges > 1)
  103.         charges = mp->quantity;
  104.     else
  105.         charges = item->MaxCharges;
  106.  
  107.     ItemInst* inst = database.CreateItem(item, charges);
  108.  
  109.     int SinglePrice = 0;
  110.     if (RuleB(Merchant, UsePriceMod))
  111.         SinglePrice = (item->Price * (RuleR(Merchant, SellCostMod)) * item->SellRate * Client::CalcPriceMod(tmp, false));
  112.     else
  113.         SinglePrice = (item->Price * (RuleR(Merchant, SellCostMod)) * item->SellRate);
  114.  
  115.     if (item->MaxCharges > 1)
  116.         mpo->price = SinglePrice;
  117.     else
  118.         mpo->price = SinglePrice * mp->quantity;
  119.     if (mpo->price < 0)
  120.     {
  121.         safe_delete(outapp);
  122.         safe_delete(inst);
  123.         return;
  124.     }
  125.  
  126.     // this area needs some work..two inventory insertion check failure points
  127.     // below do not return player's money..is this the intended behavior?
  128.  
  129.     if (!TakeMoneyFromPP(mpo->price))
  130.     {
  131.         char *hacker_str = nullptr;
  132.         MakeAnyLenString(&hacker_str, "Vendor Cheat: attempted to buy %i of %i: %s that cost %d cp but only has %d pp %d gp %d sp %d cp\n",
  133.             mpo->quantity, item->ID, item->Name,
  134.             mpo->price, m_pp.platinum, m_pp.gold, m_pp.silver, m_pp.copper);
  135.         database.SetMQDetectionFlag(AccountName(), GetName(), hacker_str, zone->GetShortName());
  136.         safe_delete_array(hacker_str);
  137.         safe_delete(outapp);
  138.         safe_delete(inst);
  139.         return;
  140.     }
  141.  
  142.     bool stacked = TryStacking(inst);
  143.     if (!stacked)
  144.         freeslotid = m_inv.FindFreeSlot(false, true, item->Size);
  145.  
  146.     // shouldn't we be reimbursing if these two fail?
  147.  
  148.     //make sure we are not completely full...
  149.     if (freeslotid == MainCursor) {
  150.         if (m_inv.GetItem(MainCursor) != nullptr) {
  151.             Message(13, "You do not have room for any more items.");
  152.             safe_delete(outapp);
  153.             safe_delete(inst);
  154.             return;
  155.         }
  156.     }
  157.  
  158.     if (!stacked && freeslotid == INVALID_INDEX)
  159.     {
  160.         Message(13, "You do not have room for any more items.");
  161.         safe_delete(outapp);
  162.         safe_delete(inst);
  163.         return;
  164.     }
  165.  
  166.     std::string packet;
  167.     if (!stacked && inst) {
  168.         PutItemInInventory(freeslotid, *inst);
  169.         SendItemPacket(freeslotid, inst, ItemPacketTrade);
  170.     }
  171.     else if (!stacked){
  172.         LogFile->write(EQEMuLog::Error, "OP_ShopPlayerBuy: item->ItemClass Unknown! Type: %i", item->ItemClass);
  173.     }
  174.     QueuePacket(outapp);
  175.     if (inst && tmpmer_used){
  176.         int32 new_charges = prevcharges - mp->quantity;
  177.         zone->SaveTempItem(merchantid, tmp->GetNPCTypeID(), item_id, new_charges);
  178.         if (new_charges <= 0){
  179.             EQApplicationPacket* delitempacket = new EQApplicationPacket(OP_ShopDelItem, sizeof(Merchant_DelItem_Struct));
  180.             Merchant_DelItem_Struct* delitem = (Merchant_DelItem_Struct*)delitempacket->pBuffer;
  181.             delitem->itemslot = mp->itemslot;
  182.             delitem->npcid = mp->npcid;
  183.             delitem->playerid = mp->playerid;
  184.             delitempacket->priority = 6;
  185.             entity_list.QueueClients(tmp, delitempacket); //que for anyone that could be using the merchant so they see the update
  186.             safe_delete(delitempacket);
  187.         }
  188.         else {
  189.             // Update the charges/quantity in the merchant window
  190.             inst->SetCharges(new_charges);
  191.             inst->SetPrice(SinglePrice);
  192.             inst->SetMerchantSlot(mp->itemslot);
  193.             inst->SetMerchantCount(new_charges);
  194.  
  195.             SendItemPacket(mp->itemslot, inst, ItemPacketMerchant);
  196.         }
  197.     }
  198.     safe_delete(inst);
  199.     safe_delete(outapp);
  200.  
  201.     // start QS code
  202.     // stacking purchases not supported at this time - entire process will need some work to catch them properly
  203.     if (RuleB(QueryServ, PlayerLogMerchantTransactions)) {
  204.         ServerPacket* qspack = new ServerPacket(ServerOP_QSPlayerLogMerchantTransactions, sizeof(QSMerchantLogTransaction_Struct)+sizeof(QSTransactionItems_Struct));
  205.         QSMerchantLogTransaction_Struct* qsaudit = (QSMerchantLogTransaction_Struct*)qspack->pBuffer;
  206.  
  207.         qsaudit->zone_id = zone->GetZoneID();
  208.         qsaudit->merchant_id = tmp->CastToNPC()->MerchantType;
  209.         qsaudit->merchant_money.platinum = 0;
  210.         qsaudit->merchant_money.gold = 0;
  211.         qsaudit->merchant_money.silver = 0;
  212.         qsaudit->merchant_money.copper = 0;
  213.         qsaudit->merchant_count = 1;
  214.         qsaudit->char_id = character_id;
  215.         qsaudit->char_money.platinum = (mpo->price / 1000);
  216.         qsaudit->char_money.gold = (mpo->price / 100) % 10;
  217.         qsaudit->char_money.silver = (mpo->price / 10) % 10;
  218.         qsaudit->char_money.copper = mpo->price % 10;
  219.         qsaudit->char_count = 0;
  220.  
  221.         qsaudit->items[0].char_slot = freeslotid == INVALID_INDEX ? 0 : freeslotid;
  222.         qsaudit->items[0].item_id = item->ID;
  223.         qsaudit->items[0].charges = mpo->quantity;
  224.        
  225.         if(freeslotid == INVALID_INDEX) {
  226.             qsaudit->items[0].aug_1 = 0;
  227.             qsaudit->items[0].aug_2 = 0;
  228.             qsaudit->items[0].aug_3 = 0;
  229.             qsaudit->items[0].aug_4 = 0;
  230.             qsaudit->items[0].aug_5 = 0;
  231.         } else {
  232.             qsaudit->items[0].aug_1 = m_inv[freeslotid]->GetAugmentItemID(0);
  233.             qsaudit->items[0].aug_2 = m_inv[freeslotid]->GetAugmentItemID(1);
  234.             qsaudit->items[0].aug_3 = m_inv[freeslotid]->GetAugmentItemID(2);
  235.             qsaudit->items[0].aug_4 = m_inv[freeslotid]->GetAugmentItemID(3);
  236.             qsaudit->items[0].aug_5 = m_inv[freeslotid]->GetAugmentItemID(4);
  237.         }
  238.  
  239.         qspack->Deflate();
  240.         if (worldserver.Connected()) { worldserver.SendPacket(qspack); }
  241.         safe_delete(qspack);
  242.     }
  243.     // end QS code
  244.  
  245.     if (RuleB(EventLog, RecordBuyFromMerchant))
  246.         LogMerchant(this, tmp, mpo->quantity, mpo->price, item, true);
  247.  
  248.     if ((RuleB(Character, EnableDiscoveredItems)))
  249.     {
  250.         if (!GetGM() && !IsDiscovered(item_id))
  251.             DiscoverItem(item_id);
  252.     }
  253.  
  254.     t1.stop();
  255.     std::cout << "At 1: " << t1.getDuration() << std::endl;
  256.     return;
  257. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement