fix(Core/Player): remove vendor icon if there is no gossip vendor option (#23026)

This commit is contained in:
sogladev
2025-10-12 17:12:54 +02:00
committed by GitHub
parent 717379628b
commit fc39bf6753
4 changed files with 79 additions and 3 deletions

View File

@@ -0,0 +1,6 @@
--
DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=23 AND `SourceEntry`=0 AND `SourceId`=0 AND `SourceGroup` IN (3443, 12919, 15471);
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 15) AND (`SourceGroup` = 9087) AND (`SourceEntry` = 0) AND (`SourceId` = 0) AND (`ElseGroup` = 0) AND (`ConditionTypeOrReference` = 12) AND (`ConditionTarget` = 0) AND (`ConditionValue1` = 109) AND (`ConditionValue2` = 0) AND (`ConditionValue3` = 0);
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(15, 9087, 0, 0, 0, 12, 0, 109, 0, 0, 0, 0, 0, '', 'event \'Sun\'s Reach Reclamation Phase Anvil\' must be active');

View File

@@ -90,6 +90,7 @@
#include "WorldStateDefines.h"
#include "WorldStatePackets.h"
#include <cmath>
#include <queue>
/// @todo: this import is not necessary for compilation and marked as unused by the IDE
// however, for some reasons removing it would cause a damn linking issue
@@ -14364,6 +14365,67 @@ bool Player::CanSeeSpellClickOn(Creature const* c) const
return false;
}
/**
* @brief Checks if any vendor option is available in the gossip menu tree for a given creature.
*
* @param menuId The starting gossip menu ID to check.
* @param creature Pointer to the creature whose gossip menus are being checked.
* @return true if a vendor option is available in any accessible menu; false otherwise.
*/
bool Player::AnyVendorOptionAvailable(uint32 menuId, Creature const* creature) const
{
std::set<uint32> visitedMenus;
std::queue<uint32> menusToCheck;
menusToCheck.push(menuId);
while (!menusToCheck.empty())
{
uint32 const currentMenuId = menusToCheck.front();
menusToCheck.pop();
if (visitedMenus.find(currentMenuId) != visitedMenus.end())
continue;
visitedMenus.insert(currentMenuId);
GossipMenuItemsMapBounds menuItemBounds = sObjectMgr->GetGossipMenuItemsMapBounds(currentMenuId);
if (menuItemBounds.first == menuItemBounds.second && currentMenuId != 0)
continue;
for (auto itr = menuItemBounds.first; itr != menuItemBounds.second; ++itr)
{
if (!sConditionMgr->IsObjectMeetToConditions(const_cast<Player*>(this), const_cast<Creature*>(creature), itr->second.Conditions))
continue;
if (itr->second.OptionType == GOSSIP_OPTION_VENDOR)
return true;
else if (itr->second.ActionMenuID)
{
GossipMenusMapBounds menuBounds = sObjectMgr->GetGossipMenusMapBounds(itr->second.ActionMenuID);
bool menuAccessible = false;
if (menuBounds.first == menuBounds.second)
menuAccessible = true;
else
{
for (auto menuItr = menuBounds.first; menuItr != menuBounds.second; ++menuItr)
if (sConditionMgr->IsObjectMeetToConditions(const_cast<Player*>(this), const_cast<Creature*>(creature), menuItr->second.Conditions))
{
menuAccessible = true;
break;
}
}
if (menuAccessible)
menusToCheck.push(itr->second.ActionMenuID);
}
}
}
return false;
}
bool Player::CanSeeVendor(Creature const* creature) const
{
if (!creature->HasNpcFlag(UNIT_NPC_FLAG_VENDOR))
@@ -14371,9 +14433,11 @@ bool Player::CanSeeVendor(Creature const* creature) const
ConditionList conditions = sConditionMgr->GetConditionsForNpcVendorEvent(creature->GetEntry(), 0);
if (!sConditionMgr->IsObjectMeetToConditions(const_cast<Player*>(this), const_cast<Creature*>(creature), conditions))
{
return false;
}
uint32 const menuId = creature->GetCreatureTemplate()->GossipMenuId;
if (!AnyVendorOptionAvailable(menuId, creature))
return false;
return true;
}

View File

@@ -41,6 +41,7 @@
#include "TradeData.h"
#include "Unit.h"
#include "WorldSession.h"
#include <set>
#include <string>
#include <vector>
@@ -2548,7 +2549,9 @@ public:
//bool isActiveObject() const { return true; }
bool CanSeeSpellClickOn(Creature const* creature) const;
[[nodiscard]] bool CanSeeVendor(Creature const* creature) const;
private:
[[nodiscard]] bool AnyVendorOptionAvailable(uint32 menuId, Creature const* creature) const;
public:
[[nodiscard]] uint32 GetChampioningFaction() const { return m_ChampioningFaction; }
void SetChampioningFaction(uint32 faction) { m_ChampioningFaction = faction; }
Spell* m_spellModTakingSpell;

View File

@@ -20791,7 +20791,10 @@ void Unit::PatchValuesUpdate(ByteBuffer& valuesUpdateBuf, BuildValuesCachePosPoi
appendValue &= ~UNIT_NPC_FLAG_SPELLCLICK;
if (!target->CanSeeVendor(creature))
{
appendValue &= ~UNIT_NPC_FLAG_REPAIR;
appendValue &= ~UNIT_NPC_FLAG_VENDOR_MASK;
}
if (!creature->IsValidTrainerForPlayer(target, &appendValue))
appendValue &= ~UNIT_NPC_FLAG_TRAINER;