Skip to content

Instantly share code, notes, and snippets.

@devovh
Forked from Rochet2/!MultiVendor.md
Created June 19, 2014 01:08
Show Gist options
  • Save devovh/79bcf12d7449a1dc3f7a to your computer and use it in GitHub Desktop.
Save devovh/79bcf12d7449a1dc3f7a to your computer and use it in GitHub Desktop.

####About Allows you to show gossip options that show different vendors from npc_vendor.
http://rochet2.github.io/?page=Multivendor

####Installation Download gist
Apply the the diff with git bash using command git apply MultiVendor.diff
Supported TC version: https://github.com/TrinityCore/TrinityCore/commit/f312b869417d5bc0ea10928284d040e04259c1d8

####Usage Set your NPC to have gossip and vendor NPCflags (129)
Add a gossip menu for him and add a new option to it.
The option needs to have option_id set to 3 so it acts as a vendor button,
npc_option_npcflag can be 1 or 128 (shows only if the NPC has vendor flag then)
and the action_menu_id is the vendor entry from npc_vendor that you want to show to the player.

YOU CAN also send menus from C++. All you need to do is to provide the vendor entry to the
void WorldSession::SendListInventory(uint64 vendorGuid, uint32 vendorEntry) function.

The npc add item command was modified so you can add items to multivendors as well.
The last vendor window must have been the multivendor you want to add your item to.
After opening the window you need to type .npc add item #itemId <#maxcount><#incrtime><#extendedcost> 1
The 1 in the end specifies that you are adding the item to the multivendor currently open.
Same thing works with .npc delete item #itemId 1

diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index f30c989..8bce7fa 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -14380,7 +14380,7 @@ void Player::PrepareGossipMenu(WorldObject* source, uint32 menuId /*= 0*/, bool
break;
case GOSSIP_OPTION_VENDOR:
{
- VendorItemData const* vendorItems = creature->GetVendorItems();
+ VendorItemData const* vendorItems = itr->second.ActionMenuId ? sObjectMgr->GetNpcVendorItemList(itr->second.ActionMenuId) : creature->GetVendorItems();
if (!vendorItems || vendorItems->Empty())
{
TC_LOG_ERROR("sql.sql", "Creature %s (Entry: %u GUID: %u DB GUID: %u) has UNIT_NPC_FLAG_VENDOR set but has an empty trading item list.", creature->GetName().c_str(), creature->GetEntry(), creature->GetGUIDLow(), creature->GetDBTableGUIDLow());
@@ -14591,7 +14591,7 @@ void Player::OnGossipSelect(WorldObject* source, uint32 gossipListId, uint32 men
break;
case GOSSIP_OPTION_VENDOR:
case GOSSIP_OPTION_ARMORER:
- GetSession()->SendListInventory(guid);
+ GetSession()->SendListInventory(guid, menuItemData->GossipActionMenuId);
break;
case GOSSIP_OPTION_STABLEPET:
GetSession()->SendStablePet(guid);
@@ -21682,7 +21682,10 @@ bool Player::BuyItemFromVendorSlot(uint64 vendorguid, uint32 vendorslot, uint32
return false;
}
- VendorItemData const* vItems = creature->GetVendorItems();
+ uint32 currentVendor = GetSession()->GetCurrentVendor();
+ if (currentVendor && vendorguid != PlayerTalkClass->GetGossipMenu().GetSenderGUID())
+ return false; // Cheating
+ VendorItemData const* vItems = currentVendor ? sObjectMgr->GetNpcVendorItemList(currentVendor) : creature->GetVendorItems();
if (!vItems || vItems->Empty())
{
SendBuyError(BUY_ERR_CANT_FIND_ITEM, creature, item, 0);
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index 207f80e..70b0516 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -8428,6 +8428,7 @@ bool ObjectMgr::RemoveVendorItem(uint32 entry, uint32 item, bool persist /*= tru
bool ObjectMgr::IsVendorItemValid(uint32 vendor_entry, uint32 item_id, int32 maxcount, uint32 incrtime, uint32 ExtendedCost, Player* player, std::set<uint32>* skip_vendors, uint32 ORnpcflag) const
{
+ /*
CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(vendor_entry);
if (!cInfo)
{
@@ -8452,6 +8453,7 @@ bool ObjectMgr::IsVendorItemValid(uint32 vendor_entry, uint32 item_id, int32 max
}
return false;
}
+ */
if (!sObjectMgr->GetItemTemplate(item_id))
{
diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp
index c4b4b35..4b29be9 100644
--- a/src/server/game/Handlers/ItemHandler.cpp
+++ b/src/server/game/Handlers/ItemHandler.cpp
@@ -717,7 +717,7 @@ void WorldSession::HandleListInventoryOpcode(WorldPacket& recvData)
SendListInventory(guid);
}
-void WorldSession::SendListInventory(uint64 vendorGuid)
+void WorldSession::SendListInventory(uint64 vendorGuid, uint32 vendorEntry)
{
TC_LOG_DEBUG("network", "WORLD: Sent SMSG_LIST_INVENTORY");
@@ -737,7 +737,7 @@ void WorldSession::SendListInventory(uint64 vendorGuid)
if (vendor->HasUnitState(UNIT_STATE_MOVING))
vendor->StopMoving();
- VendorItemData const* items = vendor->GetVendorItems();
+ VendorItemData const* items = vendorEntry ? sObjectMgr->GetNpcVendorItemList(vendorEntry) : vendor->GetVendorItems();
if (!items)
{
WorldPacket data(SMSG_LIST_INVENTORY, 8 + 1 + 1);
@@ -748,6 +748,8 @@ void WorldSession::SendListInventory(uint64 vendorGuid)
return;
}
+ SetCurrentVendor(vendorEntry);
+
uint8 itemCount = items->GetItemCount();
uint8 count = 0;
diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp
index 098cc6a..c8c7719 100644
--- a/src/server/game/Server/WorldSession.cpp
+++ b/src/server/game/Server/WorldSession.cpp
@@ -121,6 +121,7 @@ WorldSession::WorldSession(uint32 id, WorldSocket* sock, AccountTypes sec, uint8
m_TutorialsChanged(false),
recruiterId(recruiter),
isRecruiter(isARecruiter),
+ m_CurrentVendor(0),
_RBACData(NULL)
{
memset(m_Tutorials, 0, sizeof(m_Tutorials));
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index 1b16ce8..2f812d7 100644
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -244,6 +244,9 @@ class WorldSession
std::string const& GetPlayerName() const;
std::string GetPlayerInfo() const;
+ uint32 GetCurrentVendor() const { return m_CurrentVendor; }
+ void SetCurrentVendor(uint32 vendorEntry) { m_CurrentVendor = vendorEntry; }
+
uint32 GetGuidLow() const;
void SetSecurity(AccountTypes security) { _security = security; }
std::string const& GetRemoteAddress() { return m_Address; }
@@ -284,7 +287,7 @@ class WorldSession
void SendTrainerList(uint64 guid);
void SendTrainerList(uint64 guid, std::string const& strTitle);
- void SendListInventory(uint64 guid);
+ void SendListInventory(uint64 guid, uint32 vendorEntry = 0);
void SendShowBank(uint64 guid);
bool CanOpenMailBox(uint64 guid);
void SendShowMailBox(uint64 guid);
@@ -993,6 +996,7 @@ class WorldSession
Player* _player;
WorldSocket* m_Socket;
std::string m_Address;
+ uint32 m_CurrentVendor;
AccountTypes _security;
uint32 _accountId;
diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp
index 28d49fe..3b58aeb 100644
--- a/src/server/scripts/Commands/cs_npc.cpp
+++ b/src/server/scripts/Commands/cs_npc.cpp
@@ -322,7 +322,8 @@ public:
return false;
}
- uint32 vendor_entry = vendor->GetEntry();
+ char* addMulti = strtok(NULL, " ");
+ uint32 vendor_entry = addMulti ? handler->GetSession()->GetCurrentVendor() : vendor ? vendor->GetEntry() : 0;
if (!sObjectMgr->IsVendorItemValid(vendor_entry, itemId, maxcount, incrtime, extendedcost, handler->GetSession()->GetPlayer()))
{
@@ -545,7 +546,8 @@ public:
}
uint32 itemId = atol(pitem);
- if (!sObjectMgr->RemoveVendorItem(vendor->GetEntry(), itemId))
+ char* addMulti = strtok(NULL, " ");
+ if (!sObjectMgr->RemoveVendorItem(addMulti ? handler->GetSession()->GetCurrentVendor() : vendor->GetEntry(), itemId))
{
handler->PSendSysMessage(LANG_ITEM_NOT_IN_LIST, itemId);
handler->SetSentErrorMessage(true);
SET @ENTRY = (SELECT max(entry)+1 FROM creature_template);
SET @MENU_ID = (SELECT max(menu_id)+1 FROM gossip_menu_option);
INSERT INTO `creature_template` (`entry`, `modelid1`, `name`, `subname`, `IconName`, `gossip_menu_id`, `minlevel`, `maxlevel`, `exp`, `faction_A`, `faction_H`, `npcflag`, `speed_walk`, `speed_run`, `scale`, `rank`, `mindmg`, `maxdmg`, `dmgschool`, `attackpower`, `dmg_multiplier`, `baseattacktime`, `rangeattacktime`, `unit_class`, `unit_flags`, `unit_flags2`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `trainer_class`, `trainer_race`, `minrangedmg`, `maxrangedmg`, `rangedattackpower`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `PetSpellDataId`, `VehicleId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `InhabitType`, `HoverHeight`, `Health_mod`, `Mana_mod`, `Armor_mod`, `RacialLeader`, `movementId`, `RegenHealth`, `mechanic_immune_mask`, `flags_extra`, `ScriptName`, `WDBVerified`) VALUES
(@ENTRY, 1298, "Herbert", "MultiVendor", NULL, @MENU_ID, 10, 10, 0, 35, 35, 129, 1, 1.14286, 1, 0, 13, 17, 0, 42, 1, 1500, 0, 1, 512, 2048, 8, 0, 0, 0, 0, 0, 9, 13, 100, 7, 138412032, 0, 0, 0, 0, 0, 0, 0, '', 0, 3, 1, 1, 1, 1, 0, 0, 1, 0, 2, '', 0);
INSERT INTO `gossip_menu_option` (`menu_id`, `id`, `option_icon`, `option_text`, `option_id`, `npc_option_npcflag`, `action_menu_id`, `action_poi_id`, `box_coded`, `box_money`, `box_text`) VALUES
(@MENU_ID, 0, 4, 'VendorTest 465', 3, 128, 465, 0, 0, 0, ''),
(@MENU_ID, 1, 9, 'VendorTest 54', 3, 128, 54, 0, 0, 0, ''),
(@MENU_ID, 2, 6, 'VendorTest 35574', 3, 128, 35574, 0, 0, 100, 'These goods are special, so pay up!');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment