Permalink
Browse files

Add support for vendors selling the same items with different extende…

…dCost - original code by Vladimir (thanks mate)

Closes issue #1756

--HG--
branch : trunk
  • Loading branch information...
1 parent 4b1a991 commit 697685c3f57ffb9498e1a957333ea4fa6dd87b9a click committed Apr 30, 2010
@@ -0,0 +1,2 @@
+ALTER TABLE npc_vendor DROP PRIMARY KEY,
+ADD PRIMARY KEY (`entry`,`item`,`ExtendedCost`);
@@ -0,0 +1,3 @@
+DELETE FROM trinity_string WHERE entry in (210);
+INSERT INTO trinity_string VALUES
+(210,'Item ''%i'' (with extended cost %u) already in vendor list', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
View
@@ -62,29 +62,22 @@ TrainerSpell const* TrainerSpellData::Find(uint32 spell_id) const
bool VendorItemData::RemoveItem(uint32 item_id)
{
+ bool found = false;
for (VendorItemList::iterator i = m_items.begin(); i != m_items.end(); ++i)
{
if ((*i)->item == item_id)
{
- m_items.erase(i);
- return true;
+ i = m_items.erase(i);
+ found = true;
}
}
- return false;
-}
-
-size_t VendorItemData::FindItemSlot(uint32 item_id) const
-{
- for (size_t i = 0; i < m_items.size(); ++i)
- if (m_items[i]->item == item_id)
- return i;
- return m_items.size();
+ return found;
}
-VendorItem const* VendorItemData::FindItem(uint32 item_id) const
+VendorItem const* VendorItemData::FindItemCostPair(uint32 item_id, uint32 extendedCost) const
{
for (VendorItemList::const_iterator i = m_items.begin(); i != m_items.end(); ++i)
- if ((*i)->item == item_id)
+ if((*i)->item == item_id && (*i)->ExtendedCost == extendedCost)
return *i;
return NULL;
}
View
@@ -333,9 +333,7 @@ struct VendorItemData
m_items.push_back(new VendorItem(item, maxcount, ptime, ExtendedCost));
}
bool RemoveItem(uint32 item_id);
- VendorItem const* FindItem(uint32 item_id) const;
- size_t FindItemSlot(uint32 item_id) const;
-
+ VendorItem const* FindItemCostPair(uint32 item_id, uint32 extendedCost) const;
void Clear()
{
for (VendorItemList::const_iterator itr = m_items.begin(); itr != m_items.end(); ++itr)
@@ -650,6 +650,12 @@ void WorldSession::HandleBuyItemInSlotOpcode(WorldPacket & recv_data)
recv_data >> vendorguid >> item >> slot >> bagguid >> bagslot >> count;
+ // client expects count starting at 1, and we send vendorslot+1 to client already
+ if (slot > 0)
+ --slot;
+ else
+ return; // cheating
+
uint8 bag = NULL_BAG; // init for case invalid bagGUID
// find bag slot by bag guid
@@ -674,7 +680,7 @@ void WorldSession::HandleBuyItemInSlotOpcode(WorldPacket & recv_data)
if (bag == NULL_BAG)
return;
- GetPlayer()->BuyItemFromVendor(vendorguid,item,count,bag,bagslot);
+ GetPlayer()->BuyItemFromVendorSlot(vendorguid,slot,item,count,bag,bagslot);
}
void WorldSession::HandleBuyItemOpcode(WorldPacket & recv_data)
@@ -686,7 +692,13 @@ void WorldSession::HandleBuyItemOpcode(WorldPacket & recv_data)
recv_data >> vendorguid >> item >> slot >> count >> unk1;
- GetPlayer()->BuyItemFromVendor(vendorguid,item,count,NULL_BAG,NULL_SLOT);
+ // client expects count starting at 1, and we send vendorslot+1 to client already
+ if (slot > 0)
+ --slot;
+ else
+ return; // cheating
+
+ GetPlayer()->BuyItemFromVendorSlot(vendorguid,slot,item,count,NULL_BAG,NULL_SLOT);
}
void WorldSession::HandleListInventoryOpcode(WorldPacket & recv_data)
@@ -736,11 +748,14 @@ void WorldSession::SendListInventory(uint64 vendorguid)
data << uint64(vendorguid);
data << uint8(numitems);
+ size_t count_pos = data.wpos();
+ data << uint8(count);
+
float discountMod = _player->GetReputationPriceDiscount(pCreature);
- for (int i = 0; i < numitems; ++i)
+ for (uint8 vendorslot = 0; vendorslot < numitems; ++vendorslot )
{
- if (VendorItem const* crItem = vItems->GetItem(i))
+ if (VendorItem const* crItem = vItems->GetItem(vendorslot))
{
if (ItemPrototype const *pProto = objmgr.GetItemPrototype(crItem->item))
{
@@ -758,7 +773,7 @@ void WorldSession::SendListInventory(uint64 vendorguid)
// reputation discount
int32 price = uint32(floor(pProto->BuyPrice * discountMod));
- data << uint32(count);
+ data << uint32(vendorslot+1); // client expects counting to start at 1
data << uint32(crItem->item);
data << uint32(pProto->DisplayInfoID);
data << int32(crItem->maxcount <= 0 ? 0xFFFFFFFF : pCreature->GetVendorItemCurrentCount(crItem));
@@ -773,7 +788,7 @@ void WorldSession::SendListInventory(uint64 vendorguid)
if (count == 0 || data.size() != 8 + 1 + size_t(count) * 8 * 4)
return;
- data.put<uint8>(8, count);
+ data.put<uint8>(count_pos, count);
SendPacket(&data);
}
@@ -8617,10 +8617,9 @@ bool ObjectMgr::RemoveVendorItem(uint32 entry,uint32 item, bool savetodb)
if (iter == m_mCacheVendorItemMap.end())
return false;
- if (!iter->second.FindItem(item))
+ if(!iter->second.RemoveItem(item))
return false;
- iter->second.RemoveItem(item);
if (savetodb) WorldDatabase.PExecuteLog("DELETE FROM npc_vendor WHERE entry='%u' AND item='%u'",entry, item);
return true;
}
@@ -8691,12 +8690,12 @@ bool ObjectMgr::IsVendorItemValid(uint32 vendor_entry, uint32 item_id, int32 max
if (!vItems)
return true; // later checks for non-empty lists
- if (vItems->FindItem(item_id))
+ if(vItems->FindItemCostPair(item_id,ExtendedCost))
{
if (pl)
- ChatHandler(pl).PSendSysMessage(LANG_ITEM_ALREADY_IN_LIST,item_id);
+ ChatHandler(pl).PSendSysMessage(LANG_ITEM_ALREADY_IN_LIST, item_id, ExtendedCost);
else
- sLog.outErrorDb("Table `(game_event_)npc_vendor` has duplicate items %u for vendor (Entry: %u), ignore", item_id, vendor_entry);
+ sLog.outErrorDb( "Table `npc_vendor` has duplicate items %u (with extended cost %u) for vendor (Entry: %u), ignoring", item_id, ExtendedCost, vendor_entry);
return false;
}
View
@@ -19355,7 +19355,7 @@ void Player::InitDisplayIds()
}
// Return true is the bought item has a max count to force refresh of window by caller
-bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint8 bag, uint8 slot)
+bool Player::BuyItemFromVendorSlot(uint64 vendorguid, uint32 vendorslot, uint32 item, uint8 count, uint8 bag, uint8 slot)
{
// cheating attempt
if (count < 1) count = 1;
@@ -19389,14 +19389,19 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
return false;
}
- size_t vendor_slot = vItems->FindItemSlot(item);
- if (vendor_slot >= vItems->GetItemCount())
+ if (vendorslot >= vItems->GetItemCount())
{
- SendBuyError(BUY_ERR_CANT_FIND_ITEM, pCreature, item, 0);
+ SendBuyError( BUY_ERR_CANT_FIND_ITEM, pCreature, item, 0);
return false;
}
- VendorItem const* crItem = vItems->m_items[vendor_slot];
+ VendorItem const* crItem = vItems->GetItem(vendorslot);
+ // store diff item (cheating)
+ if(!crItem || crItem->item != item)
+ {
+ SendBuyError(BUY_ERR_CANT_FIND_ITEM, pCreature, item, 0);
+ return false;
+ }
// check current item amount if it limited
if (crItem->maxcount != 0)
@@ -19509,7 +19514,7 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
WorldPacket data(SMSG_BUY_ITEM, (8+4+4+4));
data << uint64(pCreature->GetGUID());
- data << uint32(vendor_slot+1); // numbered from 1 at client
+ data << uint32(vendorslot+1); // numbered from 1 at client
data << int32(crItem->maxcount > 0 ? new_count : 0xFFFFFFFF);
data << uint32(count);
GetSession()->SendPacket(&data);
@@ -19564,7 +19569,7 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
WorldPacket data(SMSG_BUY_ITEM, (8+4+4+4));
data << uint64(pCreature->GetGUID());
- data << uint32(vendor_slot + 1); // numbered from 1 at client
+ data << uint32(vendorslot + 1); // numbered from 1 at client
data << int32(crItem->maxcount > 0 ? new_count : 0xFFFFFFFF);
data << uint32(count);
GetSession()->SendPacket(&data);
@@ -23755,4 +23760,4 @@ void Player::RefundItem(Item *item)
if (arenaRefund)
ModifyArenaPoints(arenaRefund);
-}
+}
View
@@ -1251,7 +1251,7 @@ class Player : public Unit, public GridObject<Player>
return mainItem && mainItem->GetProto()->InventoryType == INVTYPE_2HWEAPON && !CanTitanGrip();
}
void SendNewItem(Item *item, uint32 count, bool received, bool created, bool broadcast = false);
- bool BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint8 bag, uint8 slot);
+ bool BuyItemFromVendorSlot(uint64 vendorguid, uint32 vendorslot, uint32 item, uint8 count, uint8 bag, uint8 slot);
float GetReputationPriceDiscount(Creature const* pCreature) const;
Player* GetTrader() const { return pTrader; }

0 comments on commit 697685c

Please sign in to comment.