Skip to content

Instantly share code, notes, and snippets.

@Rochet2
Last active September 24, 2016 05:20
Show Gist options
  • Save Rochet2/8792703 to your computer and use it in GitHub Desktop.
Save Rochet2/8792703 to your computer and use it in GitHub Desktop.
TrinityCore | Allows you to show gossip options that show different vendors from npc_vendor | http://rochet2.github.io/Multivendor.html

#UPDATE This file is outdated! updated version at http://rochet2.github.io/Multivendor.html

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

####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/2042b095266cabd79b26d8325d4dee600260d4c9

####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 9fac78b..6ca404c 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -14382,7 +14382,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());
@@ -14593,7 +14593,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);
@@ -21683,7 +21683,11 @@ 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 278460e..1ea66c0 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -8493,6 +8493,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)
{
@@ -8517,6 +8518,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 60966ac..b18aea0 100644
--- a/src/server/game/Handlers/ItemHandler.cpp
+++ b/src/server/game/Handlers/ItemHandler.cpp
@@ -728,7 +728,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");
@@ -748,7 +748,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);
@@ -759,6 +759,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 9f8b378..44e5823 100644
--- a/src/server/game/Server/WorldSession.cpp
+++ b/src/server/game/Server/WorldSession.cpp
@@ -124,7 +124,8 @@ WorldSession::WorldSession(uint32 id, WorldSocket* sock, AccountTypes sec, uint8
_RBACData(NULL),
expireTime(60000), // 1 min after socket loss, session is deleted
forceExit(false),
- m_currentBankerGUID(0)
+ m_currentBankerGUID(0),
+ m_currentVendorEntry(0)
{
memset(m_Tutorials, 0, sizeof(m_Tutorials));
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index c8c81a4..9e1875f 100644
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -245,6 +245,9 @@ class WorldSession
std::string const& GetPlayerName() const;
std::string GetPlayerInfo() const;
+ uint32 GetCurrentVendor() const { return m_currentVendorEntry; }
+ void SetCurrentVendor(uint32 vendorEntry) { m_currentVendorEntry = vendorEntry; }
+
uint32 GetGuidLow() const;
void SetSecurity(AccountTypes security) { _security = security; }
std::string const& GetRemoteAddress() { return m_Address; }
@@ -285,7 +288,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);
@@ -1014,6 +1017,7 @@ class WorldSession
uint32 expireTime;
bool forceExit;
uint64 m_currentBankerGUID;
+ uint32 m_currentVendorEntry;
WorldSession(WorldSession const& right) = delete;
WorldSession& operator=(WorldSession const& right) = delete;
diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp
index 9cf8c04..abce045 100644
--- a/src/server/scripts/Commands/cs_npc.cpp
+++ b/src/server/scripts/Commands/cs_npc.cpp
@@ -343,7 +343,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()))
{
@@ -566,7 +567,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`, `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`) VALUES
(@ENTRY, 1298, "Herbert", "MultiVendor", NULL, @MENU_ID, 10, 10, 0, 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, '');
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!');
@SleazyDev
Copy link

Thanks!

@rre-za
Copy link

rre-za commented Nov 4, 2014

Hey Rochet

iv tried to apply this to a 434 core , had a problem in ObjectMgr.cpp , seems a lil different from 335 , can u please tell me which lines should be commented in 434 source?

@Rochet2
Copy link
Author

Rochet2 commented Nov 10, 2014

iv tried to apply this to a 434 core , had a problem in ObjectMgr.cpp , seems a lil different from 335 , can u please tell me which lines should be commented in 434 source?

Its the part that loads items and checks if they are valid.
You should comment out the part that checks that the npc_vendor entry has a valid NPC entry (exists in creature_template)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment