feat(Core/Conditions): Add more support for object visibility (#25415)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
parent
62eb179385
commit
70ea8ab00b
5 changed files with 152 additions and 20 deletions
|
|
@ -836,7 +836,7 @@ uint32 Condition::GetMaxAvailableConditionTargets()
|
|||
case CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION:
|
||||
case CONDITION_SOURCE_TYPE_NPC_VENDOR:
|
||||
case CONDITION_SOURCE_TYPE_SPELL_PROC:
|
||||
case CONDITION_SOURCE_TYPE_CREATURE_VISIBILITY:
|
||||
case CONDITION_SOURCE_TYPE_OBJECT_VISIBILITY:
|
||||
return 2;
|
||||
default:
|
||||
break;
|
||||
|
|
@ -975,12 +975,12 @@ bool ConditionMgr::CanHaveSourceGroupSet(ConditionSourceType sourceType) const
|
|||
{
|
||||
return (sourceType == CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE ||
|
||||
sourceType == CONDITION_SOURCE_TYPE_PICKPOCKETING_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_PROSPECTING_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_GOSSIP_MENU || sourceType == CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION || sourceType == CONDITION_SOURCE_TYPE_VEHICLE_SPELL || sourceType == CONDITION_SOURCE_TYPE_GOSSIP_HELLO ||
|
||||
sourceType == CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET || sourceType == CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT || sourceType == CONDITION_SOURCE_TYPE_SMART_EVENT || sourceType == CONDITION_SOURCE_TYPE_NPC_VENDOR || sourceType == CONDITION_SOURCE_TYPE_PLAYER_LOOT_TEMPLATE);
|
||||
sourceType == CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET || sourceType == CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT || sourceType == CONDITION_SOURCE_TYPE_SMART_EVENT || sourceType == CONDITION_SOURCE_TYPE_NPC_VENDOR || sourceType == CONDITION_SOURCE_TYPE_PLAYER_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_OBJECT_VISIBILITY);
|
||||
}
|
||||
|
||||
bool ConditionMgr::CanHaveSourceIdSet(ConditionSourceType sourceType) const
|
||||
{
|
||||
return (sourceType == CONDITION_SOURCE_TYPE_SMART_EVENT);
|
||||
return (sourceType == CONDITION_SOURCE_TYPE_SMART_EVENT || sourceType == CONDITION_SOURCE_TYPE_OBJECT_VISIBILITY);
|
||||
}
|
||||
|
||||
ConditionList ConditionMgr::GetConditionsForNotGroupedEntry(ConditionSourceType sourceType, uint32 entry)
|
||||
|
|
@ -1073,6 +1073,43 @@ ConditionList ConditionMgr::GetConditionsForNpcVendorEvent(uint32 creatureId, ui
|
|||
return cond;
|
||||
}
|
||||
|
||||
ConditionList ConditionMgr::GetConditionsForObjectVisibility(const WorldObject* object) const
|
||||
{
|
||||
ConditionList cond;
|
||||
|
||||
if (!object->IsCreature() && !object->IsGameObject())
|
||||
return cond;
|
||||
|
||||
uint32 entry = object->GetEntry();
|
||||
uint32 sourceGroup = object->IsGameObject() ? 1 : 0;
|
||||
|
||||
auto itrBucket = ObjectVisibilityConditionStore.find(std::make_pair(entry, sourceGroup));
|
||||
if (itrBucket == ObjectVisibilityConditionStore.end())
|
||||
return cond;
|
||||
|
||||
uint32 guid = object->IsGameObject() ? object->ToGameObject()->GetSpawnId() : object->ToCreature()->GetSpawnId();
|
||||
|
||||
auto const& sourceIdConditions = itrBucket->second;
|
||||
|
||||
auto itrGuid = sourceIdConditions.find(guid);
|
||||
if (itrGuid != sourceIdConditions.end())
|
||||
{
|
||||
cond.insert(cond.end(), itrGuid->second.begin(), itrGuid->second.end());
|
||||
LOG_DEBUG("condition", "GetConditionsForObjectVisibility: found guid-level conditions for sourceGroup {} entry {} guid {}", sourceGroup, entry, guid);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto itrEntry = sourceIdConditions.find(0);
|
||||
if (itrEntry != sourceIdConditions.end())
|
||||
{
|
||||
cond.insert(cond.end(), itrEntry->second.begin(), itrEntry->second.end());
|
||||
LOG_DEBUG("condition", "GetConditionsForObjectVisibility: found entry-level conditions for sourceGroup {} entry {}", sourceGroup, entry);
|
||||
}
|
||||
}
|
||||
|
||||
return cond;
|
||||
}
|
||||
|
||||
void ConditionMgr::LoadConditions(bool isReload)
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
|
@ -1223,7 +1260,8 @@ void ConditionMgr::LoadConditions(bool isReload)
|
|||
cond->ErrorTextId = 0;
|
||||
}
|
||||
|
||||
if (cond->SourceGroup || cond->SourceType == CONDITION_SOURCE_TYPE_PLAYER_LOOT_TEMPLATE)
|
||||
if (cond->SourceGroup || cond->SourceType == CONDITION_SOURCE_TYPE_PLAYER_LOOT_TEMPLATE
|
||||
|| cond->SourceType == CONDITION_SOURCE_TYPE_OBJECT_VISIBILITY)
|
||||
{
|
||||
bool valid = false;
|
||||
// handle grouped conditions
|
||||
|
|
@ -1304,6 +1342,13 @@ void ConditionMgr::LoadConditions(bool isReload)
|
|||
++count;
|
||||
continue;
|
||||
}
|
||||
case CONDITION_SOURCE_TYPE_OBJECT_VISIBILITY:
|
||||
{
|
||||
ObjectVisibilityConditionStore[std::make_pair(uint32(cond->SourceEntry), cond->SourceGroup)][cond->SourceId].push_back(cond);
|
||||
valid = true;
|
||||
++count;
|
||||
continue; // do not add to AllocatedMemoryStore to avoid double-deleting
|
||||
}
|
||||
case CONDITION_SOURCE_TYPE_PLAYER_LOOT_TEMPLATE:
|
||||
{
|
||||
valid = addToLootTemplate(cond, LootTemplates_Player.GetLootForConditionFill(cond->SourceGroup));
|
||||
|
|
@ -1866,6 +1911,68 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond)
|
|||
}
|
||||
break;
|
||||
}
|
||||
case CONDITION_SOURCE_TYPE_OBJECT_VISIBILITY:
|
||||
{
|
||||
if (cond->SourceGroup > 1)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "CONDITION_SOURCE_TYPE_OBJECT_VISIBILITY has invalid SourceGroup {} for SourceEntry {}, expected 0 (creature) or 1 (gameobject)", cond->SourceGroup, cond->SourceEntry);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cond->SourceEntry <= 0)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "CONDITION_SOURCE_TYPE_OBJECT_VISIBILITY has invalid SourceEntry {}, expected a positive entry id.", cond->SourceEntry);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cond->SourceGroup == 0 && !sObjectMgr->GetCreatureTemplate(uint32(cond->SourceEntry)))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "CONDITION_SOURCE_TYPE_OBJECT_VISIBILITY points to non-existing creature entry {}, skipped.", cond->SourceEntry);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cond->SourceGroup == 1 && !sObjectMgr->GetGameObjectTemplate(uint32(cond->SourceEntry)))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "CONDITION_SOURCE_TYPE_OBJECT_VISIBILITY points to non-existing gameobject entry {}, skipped.", cond->SourceEntry);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cond->SourceId)
|
||||
{
|
||||
if (cond->SourceGroup == 0)
|
||||
{
|
||||
CreatureData const* data = sObjectMgr->GetCreatureData(cond->SourceId);
|
||||
if (!data)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "CONDITION_SOURCE_TYPE_OBJECT_VISIBILITY points to non-existing creature guid {}, skipped.", cond->SourceId);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data->id1 != uint32(cond->SourceEntry))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "CONDITION_SOURCE_TYPE_OBJECT_VISIBILITY has creature guid {} that does not match SourceEntry {}, skipped.", cond->SourceId, cond->SourceEntry);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GameObjectData const* data = sObjectMgr->GetGameObjectData(cond->SourceId);
|
||||
if (!data)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "CONDITION_SOURCE_TYPE_OBJECT_VISIBILITY points to non-existing gameobject guid {}, skipped.", cond->SourceId);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data->id != uint32(cond->SourceEntry))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "CONDITION_SOURCE_TYPE_OBJECT_VISIBILITY has gameobject guid {} that does not match SourceEntry {}, skipped.", cond->SourceId, cond->SourceEntry);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case CONDITION_SOURCE_TYPE_GOSSIP_MENU:
|
||||
case CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION:
|
||||
case CONDITION_SOURCE_TYPE_SMART_EVENT:
|
||||
|
|
@ -2593,6 +2700,21 @@ void ConditionMgr::Clean()
|
|||
|
||||
NpcVendorConditionContainerStore.clear();
|
||||
|
||||
for (auto& itr : ObjectVisibilityConditionStore)
|
||||
{
|
||||
for (auto& sourceIdConds : itr.second)
|
||||
{
|
||||
for (Condition* cond : sourceIdConds.second)
|
||||
delete cond;
|
||||
|
||||
sourceIdConds.second.clear();
|
||||
}
|
||||
|
||||
itr.second.clear();
|
||||
}
|
||||
|
||||
ObjectVisibilityConditionStore.clear();
|
||||
|
||||
// this is a BIG hack, feel free to fix it if you can figure out the ConditionMgr ;)
|
||||
for (std::list<Condition*>::const_iterator itr = AllocatedMemoryStore.begin(); itr != AllocatedMemoryStore.end(); ++itr) delete *itr;
|
||||
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ enum ConditionSourceType
|
|||
CONDITION_SOURCE_TYPE_GRAVEYARD = 27, // don't use on 3.3.5a
|
||||
CONDITION_SOURCE_TYPE_PLAYER_LOOT_TEMPLATE = 28,
|
||||
CONDITION_SOURCE_TYPE_CREATURE_RESPAWN = 29,
|
||||
CONDITION_SOURCE_TYPE_CREATURE_VISIBILITY = 30,
|
||||
CONDITION_SOURCE_TYPE_OBJECT_VISIBILITY = 30,
|
||||
CONDITION_SOURCE_TYPE_MAX = 31 // placeholder
|
||||
};
|
||||
|
||||
|
|
@ -198,7 +198,7 @@ struct Condition
|
|||
ConditionSourceType SourceType; //SourceTypeOrReferenceId
|
||||
uint32 SourceGroup;
|
||||
int32 SourceEntry;
|
||||
uint32 SourceId; // So far, only used in CONDITION_SOURCE_TYPE_SMART_EVENT
|
||||
uint32 SourceId; // Used in CONDITION_SOURCE_TYPE_SMART_EVENT and CONDITION_SOURCE_TYPE_OBJECT_VISIBILITY
|
||||
uint32 ElseGroup;
|
||||
ConditionTypes ConditionType; //ConditionTypeOrReference
|
||||
uint32 ConditionValue1;
|
||||
|
|
@ -242,6 +242,7 @@ typedef std::map<ConditionSourceType, ConditionTypeContainer> ConditionContainer
|
|||
typedef std::map<uint32, ConditionTypeContainer> CreatureSpellConditionContainer;
|
||||
typedef std::map<uint32, ConditionTypeContainer> NpcVendorConditionContainer;
|
||||
typedef std::map<std::pair<int32, uint32 /*SAI source_type*/>, ConditionTypeContainer> SmartEventConditionContainer;
|
||||
typedef std::map<std::pair<uint32 /*SourceEntry*/, uint32 /*SourceGroup*/>, std::map<uint32 /*SourceId*/, ConditionList>> ObjectVisibilityConditionContainer;
|
||||
|
||||
typedef std::map<uint32, ConditionList> ConditionReferenceContainer;//only used for references
|
||||
|
||||
|
|
@ -269,6 +270,7 @@ public:
|
|||
ConditionList GetConditionsForSmartEvent(int32 entryOrGuid, uint32 eventId, uint32 sourceType);
|
||||
ConditionList GetConditionsForVehicleSpell(uint32 creatureId, uint32 spellId);
|
||||
ConditionList GetConditionsForNpcVendorEvent(uint32 creatureId, uint32 itemId);
|
||||
ConditionList GetConditionsForObjectVisibility(const WorldObject* object) const;
|
||||
|
||||
private:
|
||||
bool isSourceTypeValid(Condition* cond);
|
||||
|
|
@ -281,12 +283,13 @@ private:
|
|||
void Clean(); // free up resources
|
||||
std::list<Condition*> AllocatedMemoryStore; // some garbage collection :)
|
||||
|
||||
ConditionContainer ConditionStore;
|
||||
ConditionReferenceContainer ConditionReferenceStore;
|
||||
CreatureSpellConditionContainer VehicleSpellConditionStore;
|
||||
CreatureSpellConditionContainer SpellClickEventConditionStore;
|
||||
NpcVendorConditionContainer NpcVendorConditionContainerStore;
|
||||
SmartEventConditionContainer SmartEventConditionStore;
|
||||
ConditionContainer ConditionStore;
|
||||
ConditionReferenceContainer ConditionReferenceStore;
|
||||
CreatureSpellConditionContainer VehicleSpellConditionStore;
|
||||
CreatureSpellConditionContainer SpellClickEventConditionStore;
|
||||
NpcVendorConditionContainer NpcVendorConditionContainerStore;
|
||||
SmartEventConditionContainer SmartEventConditionStore;
|
||||
ObjectVisibilityConditionContainer ObjectVisibilityConditionStore;
|
||||
};
|
||||
|
||||
#define sConditionMgr ConditionMgr::instance()
|
||||
|
|
|
|||
|
|
@ -1770,24 +1770,23 @@ bool WorldObject::CanSeeOrDetect(WorldObject const* obj, bool ignoreStealth, boo
|
|||
if (Player const* player = ToPlayer())
|
||||
{
|
||||
if (cObj->IsAIEnabled && !cObj->AI()->CanBeSeen(player))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_CREATURE_VISIBILITY, cObj->GetEntry());
|
||||
if (!sConditionMgr->IsObjectMeetToConditions((WorldObject*)this, (WorldObject*)obj, conditions))
|
||||
{
|
||||
if (!player->CanSeeObjectByVisibilityConditions(obj))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Gameobject scripts
|
||||
if (GameObject const* goObj = obj->ToGameObject())
|
||||
{
|
||||
if (ToPlayer() && !goObj->AI()->CanBeSeen(ToPlayer()))
|
||||
if (Player const* player = ToPlayer())
|
||||
{
|
||||
return false;
|
||||
if (!goObj->AI()->CanBeSeen(player))
|
||||
return false;
|
||||
|
||||
if (!player->CanSeeObjectByVisibilityConditions(obj))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14338,6 +14338,13 @@ bool Player::CanSeeSpellClickOn(Creature const* c) const
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Player::CanSeeObjectByVisibilityConditions(WorldObject const* object) const
|
||||
{
|
||||
ConditionList conds = sConditionMgr->GetConditionsForObjectVisibility(object);
|
||||
ConditionSourceInfo info = ConditionSourceInfo(const_cast<Player*>(this), const_cast<WorldObject*>(object));
|
||||
return sConditionMgr->IsObjectMeetToConditions(info, conds);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if any vendor option is available in the gossip menu tree for a given creature.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -2581,6 +2581,7 @@ public:
|
|||
|
||||
//bool isActiveObject() const { return true; }
|
||||
bool CanSeeSpellClickOn(Creature const* creature) const;
|
||||
[[nodiscard]] bool CanSeeObjectByVisibilityConditions(WorldObject const* object) const;
|
||||
[[nodiscard]] bool CanSeeVendor(Creature const* creature) const;
|
||||
[[nodiscard]] bool CanSeeTrainer(Creature const* creature) const;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue