aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/server/game/Conditions/ConditionMgr.cpp676
-rw-r--r--src/server/game/Conditions/ConditionMgr.h89
-rw-r--r--src/server/game/Entities/Player/Player.cpp8
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp17
-rw-r--r--src/server/game/Globals/ObjectMgr.h6
-rw-r--r--src/server/game/Handlers/MiscHandler.cpp2
-rw-r--r--src/server/game/Loot/Loot.cpp6
-rw-r--r--src/server/game/Loot/Loot.h4
-rw-r--r--src/server/game/Loot/LootMgr.cpp58
-rw-r--r--src/server/game/Loot/LootMgr.h6
-rw-r--r--src/server/game/Phasing/PhaseShift.cpp2
-rw-r--r--src/server/game/Phasing/PhaseShift.h6
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.cpp4
-rw-r--r--src/server/game/Spells/Spell.cpp16
-rw-r--r--src/server/game/Spells/SpellInfo.cpp14
-rw-r--r--src/server/game/Spells/SpellInfo.h2
-rw-r--r--src/server/scripts/Commands/cs_npc.cpp2
17 files changed, 369 insertions, 549 deletions
diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp
index be2e968a056..fa0cd329750 100644
--- a/src/server/game/Conditions/ConditionMgr.cpp
+++ b/src/server/game/Conditions/ConditionMgr.cpp
@@ -57,7 +57,7 @@
#include <random>
#include <sstream>
-char const* const ConditionMgr::StaticSourceTypeData[CONDITION_SOURCE_TYPE_MAX] =
+char const* const ConditionMgr::StaticSourceTypeData[CONDITION_SOURCE_TYPE_MAX_DB_ALLOWED] =
{
"None",
"Creature Loot",
@@ -179,6 +179,15 @@ ConditionSourceInfo::ConditionSourceInfo(Map const* map)
mLastFailedCondition = nullptr;
}
+std::size_t ConditionId::GetHash() const
+{
+ std::size_t hashVal = 0;
+ Trinity::hash_combine(hashVal, SourceGroup);
+ Trinity::hash_combine(hashVal, SourceEntry);
+ Trinity::hash_combine(hashVal, SourceId);
+ return hashVal;
+}
+
// Checks if object meets the condition
// Can have CONDITION_SOURCE_TYPE_NONE && !mReferenceId if called from a special event (ie: SmartAI)
bool Condition::Meets(ConditionSourceInfo& sourceInfo) const
@@ -904,8 +913,10 @@ std::string Condition::ToString(bool ext /*= false*/) const
std::ostringstream ss;
ss << "[Condition ";
ss << "SourceType: " << SourceType;
- if (SourceType < CONDITION_SOURCE_TYPE_MAX)
+ if (SourceType < CONDITION_SOURCE_TYPE_MAX_DB_ALLOWED)
ss << " (" << ConditionMgr::StaticSourceTypeData[SourceType] << ")";
+ else if (SourceType == CONDITION_SOURCE_TYPE_REFERENCE_CONDITION)
+ ss << " (Reference)";
else
ss << " (Unknown)";
if (ConditionMgr::CanHaveSourceGroupSet(SourceType))
@@ -943,26 +954,26 @@ uint32 ConditionMgr::GetSearcherTypeMaskForConditionList(ConditionContainer cons
for (ConditionContainer::const_iterator i = conditions.begin(); i != conditions.end(); ++i)
{
// no point of having not loaded conditions in list
- ASSERT((*i)->isLoaded() && "ConditionMgr::GetSearcherTypeMaskForConditionList - not yet loaded condition found in list");
- std::map<uint32, uint32>::const_iterator itr = elseGroupSearcherTypeMasks.find((*i)->ElseGroup);
+ ASSERT(i->isLoaded() && "ConditionMgr::GetSearcherTypeMaskForConditionList - not yet loaded condition found in list");
+ std::map<uint32, uint32>::const_iterator itr = elseGroupSearcherTypeMasks.find(i->ElseGroup);
// group not filled yet, fill with widest mask possible
if (itr == elseGroupSearcherTypeMasks.end())
- elseGroupSearcherTypeMasks[(*i)->ElseGroup] = GRID_MAP_TYPE_MASK_ALL;
+ elseGroupSearcherTypeMasks[i->ElseGroup] = GRID_MAP_TYPE_MASK_ALL;
// no point of checking anymore, empty mask
else if (!itr->second)
continue;
- if ((*i)->ReferenceId) // handle reference
+ if (i->ReferenceId) // handle reference
{
- ConditionReferenceContainer::const_iterator ref = ConditionReferenceStore.find((*i)->ReferenceId);
- ASSERT(ref != ConditionReferenceStore.end() && "ConditionMgr::GetSearcherTypeMaskForConditionList - incorrect reference");
- elseGroupSearcherTypeMasks[(*i)->ElseGroup] &= GetSearcherTypeMaskForConditionList((*ref).second);
+ auto ref = ConditionStore[CONDITION_SOURCE_TYPE_REFERENCE_CONDITION].find({ i->ReferenceId, 0, 0 });
+ ASSERT(ref != ConditionStore[CONDITION_SOURCE_TYPE_REFERENCE_CONDITION].end() && "ConditionMgr::GetSearcherTypeMaskForConditionList - incorrect reference");
+ elseGroupSearcherTypeMasks[i->ElseGroup] &= GetSearcherTypeMaskForConditionList(*(ref->second));
}
else // handle normal condition
{
// object will match conditions in one ElseGroupStore only when it matches all of them
// so, let's find a smallest possible mask which satisfies all conditions
- elseGroupSearcherTypeMasks[(*i)->ElseGroup] &= (*i)->GetSearcherTypeMaskForCondition();
+ elseGroupSearcherTypeMasks[i->ElseGroup] &= i->GetSearcherTypeMaskForCondition();
}
}
// object will match condition when one of the checks in ElseGroupStore is matching
@@ -978,38 +989,35 @@ bool ConditionMgr::IsObjectMeetToConditionList(ConditionSourceInfo& sourceInfo,
{
// groupId, groupCheckPassed
std::map<uint32, bool> elseGroupStore;
- for (Condition const* condition : conditions)
+ for (Condition const& condition : conditions)
{
- TC_LOG_DEBUG("condition", "ConditionMgr::IsPlayerMeetToConditionList {} val1: {}", condition->ToString(), condition->ConditionValue1);
- if (condition->isLoaded())
+ TC_LOG_DEBUG("condition", "ConditionMgr::IsPlayerMeetToConditionList {} val1: {}", condition.ToString(), condition.ConditionValue1);
+ if (condition.isLoaded())
{
//! Find ElseGroup in ElseGroupStore
- std::map<uint32, bool>::const_iterator itr = elseGroupStore.find(condition->ElseGroup);
- //! If not found, add an entry in the store and set to true (placeholder)
- if (itr == elseGroupStore.end())
- elseGroupStore[condition->ElseGroup] = true;
- else if (!(*itr).second) //! If another condition in this group was unmatched before this, don't bother checking (the group is false anyway)
+ std::map<uint32, bool>::iterator itr = elseGroupStore.try_emplace(condition.ElseGroup, true).first;
+ if (!itr->second) //! If another condition in this group was unmatched before this, don't bother checking (the group is false anyway)
continue;
- if (condition->ReferenceId)//handle reference
+ if (condition.ReferenceId)//handle reference
{
- ConditionReferenceContainer::const_iterator ref = ConditionReferenceStore.find(condition->ReferenceId);
- if (ref != ConditionReferenceStore.end())
+ auto ref = ConditionStore[CONDITION_SOURCE_TYPE_REFERENCE_CONDITION].find({ condition.ReferenceId, 0, 0 });
+ if (ref != ConditionStore[CONDITION_SOURCE_TYPE_REFERENCE_CONDITION].end())
{
- if (!IsObjectMeetToConditionList(sourceInfo, ref->second))
- elseGroupStore[condition->ElseGroup] = false;
+ if (!IsObjectMeetToConditionList(sourceInfo, *ref->second))
+ itr->second = false;
}
else
{
TC_LOG_DEBUG("condition", "ConditionMgr::IsPlayerMeetToConditionList {} Reference template -{} not found",
- condition->ToString(), condition->ReferenceId); // checked at loading, should never happen
+ condition.ToString(), condition.ReferenceId); // checked at loading, should never happen
}
}
else //handle normal condition
{
- if (!condition->Meets(sourceInfo))
- elseGroupStore[condition->ElseGroup] = false;
+ if (!condition.Meets(sourceInfo))
+ itr->second = false;
}
}
}
@@ -1066,7 +1074,8 @@ bool ConditionMgr::CanHaveSourceGroupSet(ConditionSourceType sourceType)
sourceType == CONDITION_SOURCE_TYPE_GRAVEYARD ||
sourceType == CONDITION_SOURCE_TYPE_AREATRIGGER ||
sourceType == CONDITION_SOURCE_TYPE_TRAINER_SPELL ||
- sourceType == CONDITION_SOURCE_TYPE_OBJECT_ID_VISIBILITY);
+ sourceType == CONDITION_SOURCE_TYPE_OBJECT_ID_VISIBILITY ||
+ sourceType == CONDITION_SOURCE_TYPE_REFERENCE_CONDITION);
}
bool ConditionMgr::CanHaveSourceIdSet(ConditionSourceType sourceType)
@@ -1104,11 +1113,11 @@ bool ConditionMgr::IsObjectMeetingNotGroupedConditions(ConditionSourceType sourc
{
if (sourceType > CONDITION_SOURCE_TYPE_NONE && sourceType < CONDITION_SOURCE_TYPE_MAX)
{
- ConditionsByEntryMap::const_iterator i = ConditionStore[sourceType].find(entry);
+ auto i = ConditionStore[sourceType].find({ 0, int32(entry), 0 });
if (i != ConditionStore[sourceType].end())
{
TC_LOG_DEBUG("condition", "GetConditionsForNotGroupedEntry: found conditions for type {} and entry {}", uint32(sourceType), entry);
- return IsObjectMeetToConditions(sourceInfo, i->second);
+ return IsObjectMeetToConditions(sourceInfo, *i->second);
}
}
@@ -1130,87 +1139,66 @@ bool ConditionMgr::IsMapMeetingNotGroupedConditions(ConditionSourceType sourceTy
bool ConditionMgr::HasConditionsForNotGroupedEntry(ConditionSourceType sourceType, uint32 entry) const
{
if (sourceType > CONDITION_SOURCE_TYPE_NONE && sourceType < CONDITION_SOURCE_TYPE_MAX)
- if (ConditionStore[sourceType].find(entry) != ConditionStore[sourceType].end())
- return true;
+ return ConditionStore[sourceType].contains({ 0, int32(entry), 0 });
return false;
}
bool ConditionMgr::IsObjectMeetingSpellClickConditions(uint32 creatureId, uint32 spellId, WorldObject const* clicker, WorldObject const* target) const
{
- ConditionEntriesByCreatureIdMap::const_iterator itr = SpellClickEventConditionStore.find(creatureId);
- if (itr != SpellClickEventConditionStore.end())
+ auto itr = ConditionStore[CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT].find({ creatureId, int32(spellId), 0 });
+ if (itr != ConditionStore[CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT].end())
{
- ConditionsByEntryMap::const_iterator i = itr->second.find(spellId);
- if (i != itr->second.end())
- {
- TC_LOG_DEBUG("condition", "GetConditionsForSpellClickEvent: found conditions for SpellClickEvent entry {} spell {}", creatureId, spellId);
- ConditionSourceInfo sourceInfo(clicker, target);
- return IsObjectMeetToConditions(sourceInfo, i->second);
- }
+ TC_LOG_DEBUG("condition", "IsObjectMeetingSpellClickConditions: found conditions for SpellClickEvent entry {} spell {}", creatureId, spellId);
+ ConditionSourceInfo sourceInfo(clicker, target);
+ return IsObjectMeetToConditions(sourceInfo, *itr->second);
}
return true;
}
-ConditionContainer const* ConditionMgr::GetConditionsForSpellClickEvent(uint32 creatureId, uint32 spellId) const
+bool ConditionMgr::HasConditionsForSpellClickEvent(uint32 creatureId, uint32 spellId) const
{
- ConditionEntriesByCreatureIdMap::const_iterator itr = SpellClickEventConditionStore.find(creatureId);
- if (itr != SpellClickEventConditionStore.end())
+ auto itr = ConditionStore[CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT].find({ creatureId, int32(spellId), 0 });
+ if (itr != ConditionStore[CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT].end())
{
- ConditionsByEntryMap::const_iterator i = itr->second.find(spellId);
- if (i != itr->second.end())
- {
- TC_LOG_DEBUG("condition", "GetConditionsForSpellClickEvent: found conditions for SpellClickEvent entry {} spell {}", creatureId, spellId);
- return &i->second;
- }
+ TC_LOG_DEBUG("condition", "HasConditionsForSpellClickEvent: found conditions for SpellClickEvent entry {} spell {}", creatureId, spellId);
+ return true;
}
- return nullptr;
+ return false;
}
bool ConditionMgr::IsObjectMeetingVehicleSpellConditions(uint32 creatureId, uint32 spellId, Player const* player, Unit const* vehicle) const
{
- ConditionEntriesByCreatureIdMap::const_iterator itr = VehicleSpellConditionStore.find(creatureId);
- if (itr != VehicleSpellConditionStore.end())
+ auto itr = ConditionStore[CONDITION_SOURCE_TYPE_VEHICLE_SPELL].find({ creatureId, int32(spellId), 0 });
+ if (itr != ConditionStore[CONDITION_SOURCE_TYPE_VEHICLE_SPELL].end())
{
- ConditionsByEntryMap::const_iterator i = itr->second.find(spellId);
- if (i != itr->second.end())
- {
- TC_LOG_DEBUG("condition", "GetConditionsForVehicleSpell: found conditions for Vehicle entry {} spell {}", creatureId, spellId);
- ConditionSourceInfo sourceInfo(player, vehicle);
- return IsObjectMeetToConditions(sourceInfo, i->second);
- }
+ TC_LOG_DEBUG("condition", "GetConditionsForVehicleSpell: found conditions for Vehicle entry {} spell {}", creatureId, spellId);
+ ConditionSourceInfo sourceInfo(player, vehicle);
+ return IsObjectMeetToConditions(sourceInfo, *itr->second);
}
return true;
}
bool ConditionMgr::IsObjectMeetingSmartEventConditions(int64 entryOrGuid, uint32 eventId, uint32 sourceType, Unit const* unit, WorldObject const* baseObject) const
{
- SmartEventConditionContainer::const_iterator itr = SmartEventConditionStore.find(std::make_pair(entryOrGuid, sourceType));
- if (itr != SmartEventConditionStore.end())
+ auto itr = ConditionStore[CONDITION_SOURCE_TYPE_SMART_EVENT].find({ eventId + 1, int32(entryOrGuid), sourceType });
+ if (itr != ConditionStore[CONDITION_SOURCE_TYPE_SMART_EVENT].end())
{
- ConditionsByEntryMap::const_iterator i = itr->second.find(eventId + 1);
- if (i != itr->second.end())
- {
- TC_LOG_DEBUG("condition", "GetConditionsForSmartEvent: found conditions for Smart Event entry or guid {} eventId {}", entryOrGuid, eventId);
- ConditionSourceInfo sourceInfo(unit, baseObject);
- return IsObjectMeetToConditions(sourceInfo, i->second);
- }
+ TC_LOG_DEBUG("condition", "GetConditionsForSmartEvent: found conditions for Smart Event entry or guid {} eventId {}", entryOrGuid, eventId);
+ ConditionSourceInfo sourceInfo(unit, baseObject);
+ return IsObjectMeetToConditions(sourceInfo, *itr->second);
}
return true;
}
bool ConditionMgr::IsObjectMeetingVendorItemConditions(uint32 creatureId, uint32 itemId, Player const* player, Creature const* vendor) const
{
- ConditionEntriesByCreatureIdMap::const_iterator itr = NpcVendorConditionContainerStore.find(creatureId);
- if (itr != NpcVendorConditionContainerStore.end())
+ auto itr = ConditionStore[CONDITION_SOURCE_TYPE_NPC_VENDOR].find({ creatureId, int32(itemId), 0 });
+ if (itr != ConditionStore[CONDITION_SOURCE_TYPE_NPC_VENDOR].end())
{
- ConditionsByEntryMap::const_iterator i = (*itr).second.find(itemId);
- if (i != (*itr).second.end())
- {
- TC_LOG_DEBUG("condition", "GetConditionsForNpcVendor: found conditions for creature entry {} item {}", creatureId, itemId);
- ConditionSourceInfo sourceInfo(player, vendor);
- return IsObjectMeetToConditions(sourceInfo, i->second);
- }
+ TC_LOG_DEBUG("condition", "GetConditionsForNpcVendor: found conditions for creature entry {} item {}", creatureId, itemId);
+ ConditionSourceInfo sourceInfo(player, vendor);
+ return IsObjectMeetToConditions(sourceInfo, *itr->second);
}
return true;
}
@@ -1222,30 +1210,30 @@ bool ConditionMgr::IsSpellUsedInSpellClickConditions(uint32 spellId) const
ConditionContainer const* ConditionMgr::GetConditionsForAreaTrigger(uint32 areaTriggerId, bool isServerSide) const
{
- return Trinity::Containers::MapGetValuePtr(AreaTriggerConditionContainerStore, { areaTriggerId, isServerSide });
+ auto itr = ConditionStore[CONDITION_SOURCE_TYPE_AREATRIGGER].find({ areaTriggerId, isServerSide ? 1 : 0, 0 });
+ if (itr != ConditionStore[CONDITION_SOURCE_TYPE_AREATRIGGER].end())
+ return itr->second.get();
+ return nullptr;
}
bool ConditionMgr::IsObjectMeetingTrainerSpellConditions(uint32 trainerId, uint32 spellId, Player* player) const
{
- ConditionEntriesByCreatureIdMap::const_iterator itr = TrainerSpellConditionContainerStore.find(trainerId);
- if (itr != TrainerSpellConditionContainerStore.end())
+ auto itr = ConditionStore[CONDITION_SOURCE_TYPE_NPC_VENDOR].find({ trainerId, int32(spellId), 0 });
+ if (itr != ConditionStore[CONDITION_SOURCE_TYPE_NPC_VENDOR].end())
{
- ConditionsByEntryMap::const_iterator i = (*itr).second.find(spellId);
- if (i != (*itr).second.end())
- {
- TC_LOG_DEBUG("condition", "GetConditionsForTrainerSpell: found conditions for trainer id {} spell {}", trainerId, spellId);
- return IsObjectMeetToConditions(player, i->second);
- }
+ TC_LOG_DEBUG("condition", "IsObjectMeetingTrainerSpellConditions: found conditions for trainer id {} spell {}", trainerId, spellId);
+ return IsObjectMeetToConditions(player, *itr->second);
}
return true;
}
bool ConditionMgr::IsObjectMeetingVisibilityByObjectIdConditions(uint32 objectType, uint32 entry, WorldObject const* seer) const
{
- if (ConditionContainer const* conditions = Trinity::Containers::MapGetValuePtr(ObjectVisibilityConditionStore, { objectType, entry }))
+ auto itr = ConditionStore[CONDITION_SOURCE_TYPE_OBJECT_ID_VISIBILITY].find({ objectType, int32(entry), 0 });
+ if (itr != ConditionStore[CONDITION_SOURCE_TYPE_OBJECT_ID_VISIBILITY].end())
{
TC_LOG_DEBUG("condition", "IsObjectMeetingVisibilityByObjectIdConditions: found conditions for objectType {} entry {}", objectType, entry);
- return IsObjectMeetToConditions(seer, *conditions);
+ return IsObjectMeetToConditions(seer, *itr->second);
}
return true;
}
@@ -1265,26 +1253,6 @@ void ConditionMgr::LoadConditions(bool isReload)
//must clear all custom handled cases (groupped types) before reload
if (isReload)
{
- TC_LOG_INFO("misc", "Reseting Loot Conditions...");
- LootTemplates_Creature.ResetConditions();
- LootTemplates_Fishing.ResetConditions();
- LootTemplates_Gameobject.ResetConditions();
- LootTemplates_Item.ResetConditions();
- LootTemplates_Mail.ResetConditions();
- LootTemplates_Milling.ResetConditions();
- LootTemplates_Pickpocketing.ResetConditions();
- LootTemplates_Reference.ResetConditions();
- LootTemplates_Skinning.ResetConditions();
- LootTemplates_Disenchant.ResetConditions();
- LootTemplates_Prospecting.ResetConditions();
- LootTemplates_Spell.ResetConditions();
-
- TC_LOG_INFO("misc", "Re-Loading `gossip_menu` Table for Conditions!");
- sObjectMgr->LoadGossipMenu();
-
- TC_LOG_INFO("misc", "Re-Loading `gossip_menu_option` Table for Conditions!");
- sObjectMgr->LoadGossipMenuItems();
-
sSpellMgr->UnloadSpellInfoImplicitTargetConditionLists();
sObjectMgr->UnloadPhaseConditions();
@@ -1301,330 +1269,256 @@ void ConditionMgr::LoadConditions(bool isReload)
uint32 count = 0;
+ auto getOrInitConditions = [this](ConditionSourceType sourceType, ConditionId const& id)
+ {
+ auto [itr, inserted] = ConditionStore[sourceType].try_emplace(id, nullptr);
+ if (inserted)
+ itr->second = std::make_shared<std::vector<Condition>>();
+ return itr->second;
+ };
+
do
{
Field* fields = result->Fetch();
- Condition* cond = new Condition();
+ Condition cond;
int32 iSourceTypeOrReferenceId = fields[0].GetInt32();
- cond->SourceGroup = fields[1].GetUInt32();
- cond->SourceEntry = fields[2].GetInt32();
- cond->SourceId = fields[3].GetInt32();
- cond->ElseGroup = fields[4].GetUInt32();
+ cond.SourceGroup = fields[1].GetUInt32();
+ cond.SourceEntry = fields[2].GetInt32();
+ cond.SourceId = fields[3].GetInt32();
+ cond.ElseGroup = fields[4].GetUInt32();
int32 iConditionTypeOrReference = fields[5].GetInt32();
- cond->ConditionTarget = fields[6].GetUInt8();
- cond->ConditionValue1 = fields[7].GetUInt32();
- cond->ConditionValue2 = fields[8].GetUInt32();
- cond->ConditionValue3 = fields[9].GetUInt32();
- cond->NegativeCondition = fields[10].GetBool();
- cond->ErrorType = fields[11].GetUInt32();
- cond->ErrorTextId = fields[12].GetUInt32();
- cond->ScriptId = sObjectMgr->GetScriptId(fields[13].GetString());
+ cond.ConditionTarget = fields[6].GetUInt8();
+ cond.ConditionValue1 = fields[7].GetUInt32();
+ cond.ConditionValue2 = fields[8].GetUInt32();
+ cond.ConditionValue3 = fields[9].GetUInt32();
+ cond.NegativeCondition = fields[10].GetBool();
+ cond.ErrorType = fields[11].GetUInt32();
+ cond.ErrorTextId = fields[12].GetUInt32();
+ cond.ScriptId = sObjectMgr->GetScriptId(fields[13].GetString());
if (iConditionTypeOrReference >= 0)
- cond->ConditionType = ConditionTypes(iConditionTypeOrReference);
+ cond.ConditionType = ConditionTypes(iConditionTypeOrReference);
if (iSourceTypeOrReferenceId >= 0)
- cond->SourceType = ConditionSourceType(iSourceTypeOrReferenceId);
+ cond.SourceType = ConditionSourceType(iSourceTypeOrReferenceId);
if (iConditionTypeOrReference < 0)//it has a reference
{
if (iConditionTypeOrReference == iSourceTypeOrReferenceId)//self referencing, skip
{
TC_LOG_ERROR("sql.sql", "Condition reference {} is referencing self, skipped", iSourceTypeOrReferenceId);
- delete cond;
continue;
}
- cond->ReferenceId = uint32(abs(iConditionTypeOrReference));
+
+ cond.ReferenceId = uint32(-iConditionTypeOrReference);
char const* rowType = "reference template";
if (iSourceTypeOrReferenceId >= 0)
rowType = "reference";
//check for useless data
- if (cond->ConditionTarget)
- TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in ConditionTarget ({})!", rowType, iSourceTypeOrReferenceId, cond->ConditionTarget);
- if (cond->ConditionValue1)
- TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in value1 ({})!", rowType, iSourceTypeOrReferenceId, cond->ConditionValue1);
- if (cond->ConditionValue2)
- TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in value2 ({})!", rowType, iSourceTypeOrReferenceId, cond->ConditionValue2);
- if (cond->ConditionValue3)
- TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in value3 ({})!", rowType, iSourceTypeOrReferenceId, cond->ConditionValue3);
- if (cond->NegativeCondition)
- TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in NegativeCondition ({})!", rowType, iSourceTypeOrReferenceId, cond->NegativeCondition);
- if (cond->SourceGroup && iSourceTypeOrReferenceId < 0)
- TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in SourceGroup ({})!", rowType, iSourceTypeOrReferenceId, cond->SourceGroup);
- if (cond->SourceEntry && iSourceTypeOrReferenceId < 0)
- TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in SourceEntry ({})!", rowType, iSourceTypeOrReferenceId, cond->SourceEntry);
- }
- else if (!isConditionTypeValid(cond))//doesn't have reference, validate ConditionType
- {
- delete cond;
+ if (cond.ConditionTarget)
+ TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in ConditionTarget ({})!", rowType, iSourceTypeOrReferenceId, cond.ConditionTarget);
+ if (cond.ConditionValue1)
+ TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in value1 ({})!", rowType, iSourceTypeOrReferenceId, cond.ConditionValue1);
+ if (cond.ConditionValue2)
+ TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in value2 ({})!", rowType, iSourceTypeOrReferenceId, cond.ConditionValue2);
+ if (cond.ConditionValue3)
+ TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in value3 ({})!", rowType, iSourceTypeOrReferenceId, cond.ConditionValue3);
+ if (cond.NegativeCondition)
+ TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in NegativeCondition ({})!", rowType, iSourceTypeOrReferenceId, cond.NegativeCondition);
+ }
+ else if (!isConditionTypeValid(&cond))//doesn't have reference, validate ConditionType
continue;
- }
if (iSourceTypeOrReferenceId < 0)//it is a reference template
{
- ConditionReferenceStore[std::abs(iSourceTypeOrReferenceId)].push_back(cond);//add to reference storage
- ++count;
- continue;
- }//end of reference templates
+ if (cond.SourceGroup)
+ TC_LOG_ERROR("sql.sql", "Condition reference template {} has useless data in SourceGroup ({})!", iSourceTypeOrReferenceId, cond.SourceGroup);
+ if (cond.SourceEntry)
+ TC_LOG_ERROR("sql.sql", "Condition reference template {} has useless data in SourceEntry ({})!", iSourceTypeOrReferenceId, cond.SourceEntry);
+ if (cond.SourceId)
+ TC_LOG_ERROR("sql.sql", "Condition reference template {} has useless data in SourceId ({})!", iSourceTypeOrReferenceId, cond.SourceId);
- //if not a reference and SourceType is invalid, skip
- if (iConditionTypeOrReference >= 0 && !isSourceTypeValid(cond))
- {
- delete cond;
- continue;
+ cond.SourceType = CONDITION_SOURCE_TYPE_REFERENCE_CONDITION;
+ cond.SourceGroup = -iSourceTypeOrReferenceId;
}
+ else if (!isSourceTypeValid(&cond)) //if not a reference and SourceType is invalid, skip
+ continue;
//Grouping is only allowed for some types (loot templates, gossip menus, gossip items)
- if (cond->SourceGroup && !CanHaveSourceGroupSet(cond->SourceType))
+ if (cond.SourceGroup && !CanHaveSourceGroupSet(cond.SourceType))
{
- TC_LOG_ERROR("sql.sql", "{} has not allowed value of SourceGroup = {}!", cond->ToString(), cond->SourceGroup);
- delete cond;
+ TC_LOG_ERROR("sql.sql", "{} has not allowed value of SourceGroup = {}!", cond.ToString(), cond.SourceGroup);
continue;
}
- if (cond->SourceId && !CanHaveSourceIdSet(cond->SourceType))
+ if (cond.SourceId && !CanHaveSourceIdSet(cond.SourceType))
{
- TC_LOG_ERROR("sql.sql", "{} has not allowed value of SourceId = {}!", cond->ToString(), cond->SourceId);
- delete cond;
+ TC_LOG_ERROR("sql.sql", "{} has not allowed value of SourceId = {}!", cond.ToString(), cond.SourceId);
continue;
}
- if (cond->ErrorType && cond->SourceType != CONDITION_SOURCE_TYPE_SPELL)
- {
- TC_LOG_ERROR("sql.sql", "{} can't have ErrorType ({}), set to 0!", cond->ToString(), cond->ErrorType);
- cond->ErrorType = 0;
- }
-
- if (cond->ErrorTextId && !cond->ErrorType)
+ if (cond.ErrorType && cond.SourceType != CONDITION_SOURCE_TYPE_SPELL)
{
- TC_LOG_ERROR("sql.sql", "{} has any ErrorType, ErrorTextId ({}) is set, set to 0!", cond->ToString(), cond->ErrorTextId);
- cond->ErrorTextId = 0;
+ TC_LOG_ERROR("sql.sql", "{} can't have ErrorType ({}), set to 0!", cond.ToString(), cond.ErrorType);
+ cond.ErrorType = 0;
}
- if (cond->SourceGroup)
+ if (cond.ErrorTextId && !cond.ErrorType)
{
- bool valid = false;
- // handle grouped conditions
- switch (cond->SourceType)
- {
- case CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE:
- valid = addToLootTemplate(cond, LootTemplates_Creature.GetLootForConditionFill(cond->SourceGroup));
- break;
- case CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE:
- valid = addToLootTemplate(cond, LootTemplates_Disenchant.GetLootForConditionFill(cond->SourceGroup));
- break;
- case CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE:
- valid = addToLootTemplate(cond, LootTemplates_Fishing.GetLootForConditionFill(cond->SourceGroup));
- break;
- case CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE:
- valid = addToLootTemplate(cond, LootTemplates_Gameobject.GetLootForConditionFill(cond->SourceGroup));
- break;
- case CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE:
- valid = addToLootTemplate(cond, LootTemplates_Item.GetLootForConditionFill(cond->SourceGroup));
- break;
- case CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE:
- valid = addToLootTemplate(cond, LootTemplates_Mail.GetLootForConditionFill(cond->SourceGroup));
- break;
- case CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE:
- valid = addToLootTemplate(cond, LootTemplates_Milling.GetLootForConditionFill(cond->SourceGroup));
- break;
- case CONDITION_SOURCE_TYPE_PICKPOCKETING_LOOT_TEMPLATE:
- valid = addToLootTemplate(cond, LootTemplates_Pickpocketing.GetLootForConditionFill(cond->SourceGroup));
- break;
- case CONDITION_SOURCE_TYPE_PROSPECTING_LOOT_TEMPLATE:
- valid = addToLootTemplate(cond, LootTemplates_Prospecting.GetLootForConditionFill(cond->SourceGroup));
- break;
- case CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE:
- valid = addToLootTemplate(cond, LootTemplates_Reference.GetLootForConditionFill(cond->SourceGroup));
- break;
- case CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE:
- valid = addToLootTemplate(cond, LootTemplates_Skinning.GetLootForConditionFill(cond->SourceGroup));
- break;
- case CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE:
- valid = addToLootTemplate(cond, LootTemplates_Spell.GetLootForConditionFill(cond->SourceGroup));
- break;
- case CONDITION_SOURCE_TYPE_GOSSIP_MENU:
- valid = addToGossipMenus(cond);
- break;
- case CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION:
- valid = addToGossipMenuItems(cond);
- break;
- case CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT:
- {
- SpellClickEventConditionStore[cond->SourceGroup][cond->SourceEntry].push_back(cond);
- if (cond->ConditionType == CONDITION_AURA)
- SpellsUsedInSpellClickConditions.insert(cond->ConditionValue1);
- valid = true;
- ++count;
- continue; // do not add to m_AllocatedMemory to avoid double deleting
- }
- case CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET:
- valid = addToSpellImplicitTargetConditions(cond);
- break;
- case CONDITION_SOURCE_TYPE_VEHICLE_SPELL:
- {
- VehicleSpellConditionStore[cond->SourceGroup][cond->SourceEntry].push_back(cond);
- valid = true;
- ++count;
- continue; // do not add to m_AllocatedMemory to avoid double deleting
- }
- case CONDITION_SOURCE_TYPE_SMART_EVENT:
- {
- //! TODO: PAIR_32 ?
- std::pair<int32, uint32> key = std::make_pair(cond->SourceEntry, cond->SourceId);
- SmartEventConditionStore[key][cond->SourceGroup].push_back(cond);
- valid = true;
- ++count;
- continue;
- }
- case CONDITION_SOURCE_TYPE_NPC_VENDOR:
- {
- NpcVendorConditionContainerStore[cond->SourceGroup][cond->SourceEntry].push_back(cond);
- valid = true;
- ++count;
- continue;
- }
- case CONDITION_SOURCE_TYPE_PHASE:
- valid = addToPhases(cond);
- break;
- case CONDITION_SOURCE_TYPE_GRAVEYARD:
- valid = addToGraveyardData(cond);
- break;
- case CONDITION_SOURCE_TYPE_AREATRIGGER:
- {
- AreaTriggerConditionContainerStore[{ cond->SourceGroup, cond->SourceEntry }].push_back(cond);
- valid = true;
- ++count;
- continue;
- }
- case CONDITION_SOURCE_TYPE_TRAINER_SPELL:
- {
- TrainerSpellConditionContainerStore[cond->SourceGroup][cond->SourceEntry].push_back(cond);
- valid = true;
- ++count;
- continue;
- }
- case CONDITION_SOURCE_TYPE_OBJECT_ID_VISIBILITY:
- {
- ObjectVisibilityConditionStore[{ cond->SourceGroup, uint32(cond->SourceEntry) }].push_back(cond);
- valid = true;
- ++count;
- continue;
- }
- default:
- break;
- }
-
- if (!valid)
- {
- TC_LOG_ERROR("sql.sql", "{} Not handled grouped condition.", cond->ToString());
- delete cond;
- }
- else
- {
- AllocatedMemoryStore.push_back(cond);
- ++count;
- }
- continue;
+ TC_LOG_ERROR("sql.sql", "{} has any ErrorType, ErrorTextId ({}) is set, set to 0!", cond.ToString(), cond.ErrorTextId);
+ cond.ErrorTextId = 0;
}
- //handle not grouped conditions
- //add new Condition to storage based on Type/Entry
- if (cond->SourceType == CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT && cond->ConditionType == CONDITION_AURA)
- SpellsUsedInSpellClickConditions.insert(cond->ConditionValue1);
- ConditionStore[cond->SourceType][cond->SourceEntry].push_back(cond);
+ getOrInitConditions(cond.SourceType, { cond.SourceGroup, cond.SourceEntry, cond.SourceId })->emplace_back(std::move(cond));
++count;
}
while (result->NextRow());
+ for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE])
+ addToLootTemplate(id, conditions, LootTemplates_Creature.GetLootForConditionFill(id.SourceGroup));
+
+ for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE])
+ addToLootTemplate(id, conditions, LootTemplates_Disenchant.GetLootForConditionFill(id.SourceGroup));
+
+ for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE])
+ addToLootTemplate(id, conditions, LootTemplates_Fishing.GetLootForConditionFill(id.SourceGroup));
+
+ for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE])
+ addToLootTemplate(id, conditions, LootTemplates_Gameobject.GetLootForConditionFill(id.SourceGroup));
+
+ for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE])
+ addToLootTemplate(id, conditions, LootTemplates_Item.GetLootForConditionFill(id.SourceGroup));
+
+ for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE])
+ addToLootTemplate(id, conditions, LootTemplates_Mail.GetLootForConditionFill(id.SourceGroup));
+
+ for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE])
+ addToLootTemplate(id, conditions, LootTemplates_Milling.GetLootForConditionFill(id.SourceGroup));
+
+ for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_PICKPOCKETING_LOOT_TEMPLATE])
+ addToLootTemplate(id, conditions, LootTemplates_Pickpocketing.GetLootForConditionFill(id.SourceGroup));
+
+ for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_PROSPECTING_LOOT_TEMPLATE])
+ addToLootTemplate(id, conditions, LootTemplates_Prospecting.GetLootForConditionFill(id.SourceGroup));
+
+ for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE])
+ addToLootTemplate(id, conditions, LootTemplates_Reference.GetLootForConditionFill(id.SourceGroup));
+
+ for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE])
+ addToLootTemplate(id, conditions, LootTemplates_Skinning.GetLootForConditionFill(id.SourceGroup));
+
+ for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE])
+ addToLootTemplate(id, conditions, LootTemplates_Spell.GetLootForConditionFill(id.SourceGroup));
+
+ for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_GOSSIP_MENU])
+ addToGossipMenus(id, conditions);
+
+ for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION])
+ addToGossipMenuItems(id, conditions);
+
+ SpellsUsedInSpellClickConditions.clear();
+ for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT])
+ for (Condition const& condition : *conditions)
+ if (condition.ConditionType == CONDITION_AURA)
+ SpellsUsedInSpellClickConditions.insert(condition.ConditionValue1);
+
+ for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET])
+ for (Condition const& condition : *conditions)
+ addToSpellImplicitTargetConditions(condition);
+
+ for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_PHASE])
+ addToPhases(id, conditions);
+
+ for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_GRAVEYARD])
+ addToGraveyardData(id, conditions);
+
TC_LOG_INFO("server.loading", ">> Loaded {} conditions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
}
-bool ConditionMgr::addToLootTemplate(Condition* cond, LootTemplate* loot) const
+void ConditionMgr::addToLootTemplate(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions, LootTemplate* loot) const
{
if (!loot)
{
- TC_LOG_ERROR("sql.sql", "{} LootTemplate {} not found.", cond->ToString(), cond->SourceGroup);
- return false;
+ for (Condition const& condition : *conditions)
+ TC_LOG_ERROR("sql.sql", "{} LootTemplate {} not found.", condition.ToString(), id.SourceGroup);
+ return;
}
- if (loot->addConditionItem(cond))
- return true;
+ if (loot->LinkConditions(id, ConditionsReference{ conditions }))
+ return;
- TC_LOG_ERROR("sql.sql", "{} Item {} not found in LootTemplate {}.", cond->ToString(), cond->SourceEntry, cond->SourceGroup);
- return false;
+ for (Condition const& condition : *conditions)
+ TC_LOG_ERROR("sql.sql", "{} Item {} not found in LootTemplate {}.", condition.ToString(), id.SourceEntry, id.SourceGroup);
}
-bool ConditionMgr::addToGossipMenus(Condition* cond) const
+void ConditionMgr::addToGossipMenus(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions) const
{
- GossipMenusMapBoundsNonConst pMenuBounds = sObjectMgr->GetGossipMenusMapBoundsNonConst(cond->SourceGroup);
+ GossipMenusMapBoundsNonConst pMenuBounds = sObjectMgr->GetGossipMenusMapBoundsNonConst(id.SourceGroup);
if (pMenuBounds.first != pMenuBounds.second)
{
for (GossipMenusContainer::iterator itr = pMenuBounds.first; itr != pMenuBounds.second; ++itr)
- {
- if (itr->second.MenuID == cond->SourceGroup && (itr->second.TextID == uint32(cond->SourceEntry) || cond->SourceEntry == 0))
- itr->second.Conditions.push_back(cond);
- }
- return true;
+ if (itr->second.MenuID == id.SourceGroup && (itr->second.TextID == uint32(id.SourceEntry) || id.SourceEntry == 0))
+ itr->second.Conditions = { conditions };
+
+ return;
}
- TC_LOG_ERROR("sql.sql", "{} GossipMenu {} not found.", cond->ToString(), cond->SourceGroup);
- return false;
+ for (Condition const& condition : *conditions)
+ TC_LOG_ERROR("sql.sql", "{} GossipMenu {} not found.", condition.ToString(), id.SourceGroup);
}
-bool ConditionMgr::addToGossipMenuItems(Condition* cond) const
+void ConditionMgr::addToGossipMenuItems(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions) const
{
- Trinity::IteratorPair pMenuItemBounds = sObjectMgr->GetGossipMenuItemsMapBoundsNonConst(cond->SourceGroup);
+ Trinity::IteratorPair pMenuItemBounds = sObjectMgr->GetGossipMenuItemsMapBoundsNonConst(id.SourceGroup);
for (auto& [_, gossipMenuItem] : pMenuItemBounds)
{
- if (gossipMenuItem.MenuID == cond->SourceGroup && gossipMenuItem.OrderIndex == uint32(cond->SourceEntry))
+ if (gossipMenuItem.MenuID == id.SourceGroup && gossipMenuItem.OrderIndex == uint32(id.SourceEntry))
{
- gossipMenuItem.Conditions.push_back(cond);
- return true;
+ gossipMenuItem.Conditions = { conditions };
+ return;
}
}
- TC_LOG_ERROR("sql.sql", "{} GossipMenuId {} Item {} not found.", cond->ToString(), cond->SourceGroup, cond->SourceEntry);
- return false;
+ for (Condition const& condition : *conditions)
+ TC_LOG_ERROR("sql.sql", "{} GossipMenuId {} Item {} not found.", condition.ToString(), id.SourceGroup, id.SourceEntry);
}
-bool ConditionMgr::addToSpellImplicitTargetConditions(Condition* cond) const
+void ConditionMgr::addToSpellImplicitTargetConditions(Condition const& cond) const
{
- bool valid = false;
- sSpellMgr->ForEachSpellInfoDifficulty(cond->SourceEntry, [&](SpellInfo const* spellInfo)
+ sSpellMgr->ForEachSpellInfoDifficulty(cond.SourceEntry, [&](SpellInfo const* spellInfo)
{
- uint32 conditionEffMask = cond->SourceGroup;
+ uint32 conditionEffMask = cond.SourceGroup;
std::list<uint32> sharedMasks;
for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
{
// additional checks by condition type
if (conditionEffMask & (1 << spellEffectInfo.EffectIndex))
{
- switch (cond->ConditionType)
+ switch (cond.ConditionType)
{
case CONDITION_OBJECT_ENTRY_GUID:
{
uint32 implicitTargetMask = GetTargetFlagMask(spellEffectInfo.TargetA.GetObjectType()) | GetTargetFlagMask(spellEffectInfo.TargetB.GetObjectType());
- if ((implicitTargetMask & TARGET_FLAG_UNIT_MASK) && cond->ConditionValue1 != TYPEID_UNIT && cond->ConditionValue1 != TYPEID_PLAYER)
+ if ((implicitTargetMask & TARGET_FLAG_UNIT_MASK) && cond.ConditionValue1 != TYPEID_UNIT && cond.ConditionValue1 != TYPEID_PLAYER)
{
TC_LOG_ERROR("sql.sql", "{} in `condition` table - spell {} EFFECT_{} - "
- "target requires ConditionValue1 to be either TYPEID_UNIT ({}) or TYPEID_PLAYER ({})", cond->ToString(), spellInfo->Id, uint32(spellEffectInfo.EffectIndex), uint32(TYPEID_UNIT), uint32(TYPEID_PLAYER));
+ "target requires ConditionValue1 to be either TYPEID_UNIT ({}) or TYPEID_PLAYER ({})", cond.ToString(), spellInfo->Id, uint32(spellEffectInfo.EffectIndex), uint32(TYPEID_UNIT), uint32(TYPEID_PLAYER));
return;
}
- if ((implicitTargetMask & TARGET_FLAG_GAMEOBJECT_MASK) && cond->ConditionValue1 != TYPEID_GAMEOBJECT)
+ if ((implicitTargetMask & TARGET_FLAG_GAMEOBJECT_MASK) && cond.ConditionValue1 != TYPEID_GAMEOBJECT)
{
TC_LOG_ERROR("sql.sql", "{} in `condition` table - spell {} EFFECT_{} - "
- "target requires ConditionValue1 to be TYPEID_GAMEOBJECT ({})", cond->ToString(), spellInfo->Id, uint32(spellEffectInfo.EffectIndex), uint32(TYPEID_GAMEOBJECT));
+ "target requires ConditionValue1 to be TYPEID_GAMEOBJECT ({})", cond.ToString(), spellInfo->Id, uint32(spellEffectInfo.EffectIndex), uint32(TYPEID_GAMEOBJECT));
return;
}
- if ((implicitTargetMask & TARGET_FLAG_CORPSE_MASK) && cond->ConditionValue1 != TYPEID_CORPSE)
+ if ((implicitTargetMask & TARGET_FLAG_CORPSE_MASK) && cond.ConditionValue1 != TYPEID_CORPSE)
{
TC_LOG_ERROR("sql.sql", "{} in `condition` table - spell {} EFFECT_{} - "
- "target requires ConditionValue1 to be TYPEID_CORPSE ({})", cond->ToString(), spellInfo->Id, uint32(spellEffectInfo.EffectIndex), uint32(TYPEID_CORPSE));
+ "target requires ConditionValue1 to be TYPEID_CORPSE ({})", cond.ToString(), spellInfo->Id, uint32(spellEffectInfo.EffectIndex), uint32(TYPEID_CORPSE));
return;
}
break;
@@ -1641,9 +1535,8 @@ bool ConditionMgr::addToSpellImplicitTargetConditions(Condition* cond) const
// build new shared mask with found effect
uint32 sharedMask = 1 << spellEffectInfo.EffectIndex;
- ConditionContainer* cmp = spellEffectInfo.ImplicitTargetConditions;
for (size_t effIndex = spellEffectInfo.EffectIndex + 1; effIndex < spellInfo->GetEffects().size(); ++effIndex)
- if (spellInfo->GetEffect(SpellEffIndex(effIndex)).ImplicitTargetConditions == cmp)
+ if (spellInfo->GetEffect(SpellEffIndex(effIndex)).ImplicitTargetConditions == spellEffectInfo.ImplicitTargetConditions)
sharedMask |= 1 << effIndex;
sharedMasks.push_back(sharedMask);
@@ -1663,7 +1556,7 @@ bool ConditionMgr::addToSpellImplicitTargetConditions(Condition* cond) const
return;
// get shared data
- ConditionContainer* sharedList = spellInfo->GetEffect(SpellEffIndex(firstEffIndex)).ImplicitTargetConditions;
+ std::shared_ptr<ConditionContainer> sharedList = spellInfo->GetEffect(SpellEffIndex(firstEffIndex)).ImplicitTargetConditions;
// there's already data entry for that sharedMask
if (sharedList)
@@ -1673,7 +1566,7 @@ bool ConditionMgr::addToSpellImplicitTargetConditions(Condition* cond) const
{
TC_LOG_ERROR("sql.sql", "{} in `condition` table, has incorrect SourceGroup {} (spell effectMask) set - "
"effect masks are overlapping (all SourceGroup values having given bit set must be equal) - ignoring (Difficulty {}).",
- cond->ToString(), cond->SourceGroup, uint32(spellInfo->Difficulty));
+ cond.ToString(), cond.SourceGroup, uint32(spellInfo->Difficulty));
return;
}
}
@@ -1681,7 +1574,7 @@ bool ConditionMgr::addToSpellImplicitTargetConditions(Condition* cond) const
else
{
// add new list, create new shared mask
- sharedList = new ConditionContainer();
+ sharedList = std::make_shared<ConditionContainer>();
bool assigned = false;
for (size_t i = firstEffIndex; i < spellInfo->GetEffects().size(); ++i)
{
@@ -1693,25 +1586,20 @@ bool ConditionMgr::addToSpellImplicitTargetConditions(Condition* cond) const
}
if (!assigned)
- {
- delete sharedList;
break;
- }
}
sharedList->push_back(cond);
break;
}
}
- valid = true;
});
- return true;
}
-bool ConditionMgr::addToPhases(Condition* cond) const
+void ConditionMgr::addToPhases(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions) const
{
- if (!cond->SourceEntry)
+ if (!id.SourceEntry)
{
- if (PhaseInfoStruct const* phaseInfo = sObjectMgr->GetPhaseInfo(cond->SourceGroup))
+ if (PhaseInfoStruct const* phaseInfo = sObjectMgr->GetPhaseInfo(id.SourceGroup))
{
bool found = false;
for (uint32 areaId : phaseInfo->Areas)
@@ -1720,9 +1608,9 @@ bool ConditionMgr::addToPhases(Condition* cond) const
{
for (PhaseAreaInfo& phase : *phases)
{
- if (phase.PhaseInfo->Id == cond->SourceGroup)
+ if (phase.PhaseInfo->Id == id.SourceGroup)
{
- phase.Conditions.push_back(cond);
+ phase.Conditions.insert(phase.Conditions.end(), conditions->begin(), conditions->end());
found = true;
}
}
@@ -1730,35 +1618,35 @@ bool ConditionMgr::addToPhases(Condition* cond) const
}
if (found)
- return true;
+ return;
}
}
- else if (std::vector<PhaseAreaInfo>* phases = const_cast<std::vector<PhaseAreaInfo>*>(sObjectMgr->GetPhasesForArea(cond->SourceEntry)))
+ else if (std::vector<PhaseAreaInfo>* phases = const_cast<std::vector<PhaseAreaInfo>*>(sObjectMgr->GetPhasesForArea(id.SourceEntry)))
{
for (PhaseAreaInfo& phase : *phases)
{
- if (phase.PhaseInfo->Id == cond->SourceGroup)
+ if (phase.PhaseInfo->Id == id.SourceGroup)
{
- phase.Conditions.push_back(cond);
- return true;
+ phase.Conditions.insert(phase.Conditions.end(), conditions->begin(), conditions->end());
+ return;
}
}
}
- TC_LOG_ERROR("sql.sql", "{} Area {} does not have phase {}.", cond->ToString(), cond->SourceEntry, cond->SourceGroup);
- return false;
+ for (Condition const& condition : *conditions)
+ TC_LOG_ERROR("sql.sql", "{} Area {} does not have phase {}.", condition.ToString(), id.SourceEntry, id.SourceGroup);
}
-bool ConditionMgr::addToGraveyardData(Condition* cond) const
+void ConditionMgr::addToGraveyardData(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions) const
{
- if (GraveyardData* graveyard = const_cast<GraveyardData*>(sObjectMgr->FindGraveyardData(cond->SourceEntry, cond->SourceGroup)))
+ if (GraveyardData* graveyard = const_cast<GraveyardData*>(sObjectMgr->FindGraveyardData(id.SourceEntry, id.SourceGroup)))
{
- graveyard->Conditions.push_back(cond);
- return true;
+ graveyard->Conditions = { conditions };
+ return;
}
- TC_LOG_ERROR("sql.sql", "{}, Graveyard {} does not have ghostzone {}.", cond->ToString(), cond->SourceEntry, cond->SourceGroup);
- return false;
+ for (Condition const& condition : *conditions)
+ TC_LOG_ERROR("sql.sql", "{}, Graveyard {} does not have ghostzone {}.", condition.ToString(), id.SourceEntry, id.SourceGroup);
}
bool ConditionMgr::isSourceTypeValid(Condition* cond) const
@@ -2146,7 +2034,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) const
TC_LOG_ERROR("sql.sql", "{} in `condition` table, unexpected SourceEntry value (expected 0 or 1), ignoring.", cond->ToString());
return false;
}
- if (!sAreaTriggerDataStore->GetAreaTriggerTemplate({ uint32(cond->SourceGroup), bool(cond->SourceEntry) }))
+ if (!sAreaTriggerDataStore->GetAreaTriggerTemplate({ uint32(cond->SourceGroup), cond->SourceEntry == 1 }))
{
TC_LOG_ERROR("sql.sql", "{} in `condition` table, does not exist in `areatrigger_template`, ignoring.", cond->ToString());
return false;
@@ -2815,74 +2703,10 @@ void ConditionMgr::LogUselessConditionValue(Condition* cond, uint8 index, uint32
void ConditionMgr::Clean()
{
- for (ConditionReferenceContainer::iterator itr = ConditionReferenceStore.begin(); itr != ConditionReferenceStore.end(); ++itr)
- for (ConditionContainer::const_iterator it = itr->second.begin(); it != itr->second.end(); ++it)
- delete *it;
-
- ConditionReferenceStore.clear();
-
- for (uint32 i = 0; i < CONDITION_SOURCE_TYPE_MAX; ++i)
- {
- for (ConditionsByEntryMap::iterator it = ConditionStore[i].begin(); it != ConditionStore[i].end(); ++it)
- for (ConditionContainer::const_iterator itr = it->second.begin(); itr != it->second.end(); ++itr)
- delete *itr;
+ for (std::unordered_map<ConditionId, std::shared_ptr<std::vector<Condition>>>& conditionsMap : ConditionStore)
+ conditionsMap.clear();
- ConditionStore[i].clear();
- }
-
- for (ConditionEntriesByCreatureIdMap::iterator itr = VehicleSpellConditionStore.begin(); itr != VehicleSpellConditionStore.end(); ++itr)
- for (ConditionsByEntryMap::iterator it = itr->second.begin(); it != itr->second.end(); ++it)
- for (ConditionContainer::const_iterator i = it->second.begin(); i != it->second.end(); ++i)
- delete *i;
-
- VehicleSpellConditionStore.clear();
-
- for (SmartEventConditionContainer::iterator itr = SmartEventConditionStore.begin(); itr != SmartEventConditionStore.end(); ++itr)
- for (ConditionsByEntryMap::iterator it = itr->second.begin(); it != itr->second.end(); ++it)
- for (ConditionContainer::const_iterator i = it->second.begin(); i != it->second.end(); ++i)
- delete *i;
-
- SmartEventConditionStore.clear();
-
- for (ConditionEntriesByCreatureIdMap::iterator itr = SpellClickEventConditionStore.begin(); itr != SpellClickEventConditionStore.end(); ++itr)
- for (ConditionsByEntryMap::iterator it = itr->second.begin(); it != itr->second.end(); ++it)
- for (ConditionContainer::const_iterator i = it->second.begin(); i != it->second.end(); ++i)
- delete *i;
-
- SpellClickEventConditionStore.clear();
SpellsUsedInSpellClickConditions.clear();
-
- for (ConditionEntriesByCreatureIdMap::iterator itr = NpcVendorConditionContainerStore.begin(); itr != NpcVendorConditionContainerStore.end(); ++itr)
- for (ConditionsByEntryMap::iterator it = itr->second.begin(); it != itr->second.end(); ++it)
- for (ConditionContainer::const_iterator i = it->second.begin(); i != it->second.end(); ++i)
- delete *i;
-
- NpcVendorConditionContainerStore.clear();
-
- for (ConditionEntriesByAreaTriggerIdMap::iterator itr = AreaTriggerConditionContainerStore.begin(); itr != AreaTriggerConditionContainerStore.end(); ++itr)
- for (ConditionContainer::const_iterator i = itr->second.begin(); i != itr->second.end(); ++i)
- delete *i;
-
- AreaTriggerConditionContainerStore.clear();
-
- for (ConditionEntriesByCreatureIdMap::iterator itr = TrainerSpellConditionContainerStore.begin(); itr != TrainerSpellConditionContainerStore.end(); ++itr)
- for (ConditionsByEntryMap::iterator it = itr->second.begin(); it != itr->second.end(); ++it)
- for (ConditionContainer::const_iterator i = it->second.begin(); i != it->second.end(); ++i)
- delete *i;
-
- TrainerSpellConditionContainerStore.clear();
-
- for (auto&& [_, conditions] : ObjectVisibilityConditionStore)
- for (Condition* condition : conditions)
- delete condition;
-
- ObjectVisibilityConditionStore.clear();
-
- // this is a BIG hack, feel free to fix it if you can figure out the ConditionMgr ;)
- for (std::vector<Condition*>::const_iterator itr = AllocatedMemoryStore.begin(); itr != AllocatedMemoryStore.end(); ++itr)
- delete *itr;
-
- AllocatedMemoryStore.clear();
}
inline bool PlayerConditionCompare(int32 comparisonType, int32 value1, int32 value2)
diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h
index e7e94cc3a54..cedc07ed67c 100644
--- a/src/server/game/Conditions/ConditionMgr.h
+++ b/src/server/game/Conditions/ConditionMgr.h
@@ -21,6 +21,7 @@
#include "Define.h"
#include "Hash.h"
#include <array>
+#include <memory>
#include <string>
#include <unordered_map>
#include <unordered_set>
@@ -183,7 +184,10 @@ enum ConditionSourceType
CONDITION_SOURCE_TYPE_TRAINER_SPELL = 31,
CONDITION_SOURCE_TYPE_OBJECT_ID_VISIBILITY = 32,
CONDITION_SOURCE_TYPE_SPAWN_GROUP = 33,
- CONDITION_SOURCE_TYPE_MAX = 34 // MAX
+
+ CONDITION_SOURCE_TYPE_MAX_DB_ALLOWED,
+ CONDITION_SOURCE_TYPE_REFERENCE_CONDITION = CONDITION_SOURCE_TYPE_MAX_DB_ALLOWED, // internal, not set in db
+ CONDITION_SOURCE_TYPE_MAX // MAX
};
enum RelationType
@@ -219,6 +223,23 @@ struct TC_GAME_API ConditionSourceInfo
ConditionSourceInfo(Map const* map);
};
+struct TC_GAME_API ConditionId
+{
+ uint32 SourceGroup = 0;
+ int32 SourceEntry = 0;
+ uint32 SourceId = 0;
+
+ std::size_t GetHash() const;
+ bool operator==(ConditionId const& right) const = default;
+ std::strong_ordering operator<=>(ConditionId const& right) const = default;
+};
+
+template<>
+struct std::hash<ConditionId>
+{
+ std::size_t operator()(ConditionId const& id) const noexcept { return id.GetHash(); }
+};
+
struct TC_GAME_API Condition
{
ConditionSourceType SourceType; //SourceTypeOrReferenceId
@@ -264,13 +285,9 @@ struct TC_GAME_API Condition
std::string ToString(bool ext = false) const; /// For logging purpose
};
-typedef std::vector<Condition*> ConditionContainer;
-typedef std::unordered_map<uint32 /*SourceEntry*/, ConditionContainer> ConditionsByEntryMap;
+typedef std::vector<Condition> ConditionContainer;
+typedef std::unordered_map<ConditionId, std::shared_ptr<ConditionContainer>> ConditionsByEntryMap; // stored as shared_ptr to give out weak_ptrs to hold by other code (ownership not shared)
typedef std::array<ConditionsByEntryMap, CONDITION_SOURCE_TYPE_MAX> ConditionEntriesByTypeArray;
-typedef std::unordered_map<uint32, ConditionsByEntryMap> ConditionEntriesByCreatureIdMap;
-typedef std::unordered_map<std::pair<int32, uint32 /*SAI source_type*/>, ConditionsByEntryMap> SmartEventConditionContainer;
-typedef std::unordered_map<uint32, ConditionContainer> ConditionReferenceContainer;//only used for references
-typedef std::unordered_map<std::pair<int32, bool>, ConditionContainer> ConditionEntriesByAreaTriggerIdMap;
class TC_GAME_API ConditionMgr
{
@@ -296,7 +313,7 @@ class TC_GAME_API ConditionMgr
bool IsMapMeetingNotGroupedConditions(ConditionSourceType sourceType, uint32 entry, Map const* map) const;
bool HasConditionsForNotGroupedEntry(ConditionSourceType sourceType, uint32 entry) const;
bool IsObjectMeetingSpellClickConditions(uint32 creatureId, uint32 spellId, WorldObject const* clicker, WorldObject const* target) const;
- ConditionContainer const* GetConditionsForSpellClickEvent(uint32 creatureId, uint32 spellId) const;
+ bool HasConditionsForSpellClickEvent(uint32 creatureId, uint32 spellId) const;
bool IsObjectMeetingVehicleSpellConditions(uint32 creatureId, uint32 spellId, Player const* player, Unit const* vehicle) const;
bool IsObjectMeetingSmartEventConditions(int64 entryOrGuid, uint32 eventId, uint32 sourceType, Unit const* unit, WorldObject const* baseObject) const;
bool IsObjectMeetingVendorItemConditions(uint32 creatureId, uint32 itemId, Player const* player, Creature const* vendor) const;
@@ -319,37 +336,61 @@ class TC_GAME_API ConditionMgr
bool HasConditionValue2;
bool HasConditionValue3;
};
- static char const* const StaticSourceTypeData[CONDITION_SOURCE_TYPE_MAX];
+ static char const* const StaticSourceTypeData[CONDITION_SOURCE_TYPE_MAX_DB_ALLOWED];
static ConditionTypeInfo const StaticConditionTypeData[CONDITION_MAX];
private:
bool isSourceTypeValid(Condition* cond) const;
- bool addToLootTemplate(Condition* cond, LootTemplate* loot) const;
- bool addToGossipMenus(Condition* cond) const;
- bool addToGossipMenuItems(Condition* cond) const;
- bool addToSpellImplicitTargetConditions(Condition* cond) const;
- bool addToPhases(Condition* cond) const;
- bool addToGraveyardData(Condition* cond) const;
+ void addToLootTemplate(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions, LootTemplate* loot) const;
+ void addToGossipMenus(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions) const;
+ void addToGossipMenuItems(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions) const;
+ void addToSpellImplicitTargetConditions(Condition const& cond) const;
+ void addToPhases(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions) const;
+ void addToGraveyardData(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions) const;
bool IsObjectMeetToConditionList(ConditionSourceInfo& sourceInfo, ConditionContainer const& conditions) const;
static void LogUselessConditionValue(Condition* cond, uint8 index, uint32 value);
void Clean(); // free up resources
- std::vector<Condition*> AllocatedMemoryStore; // some garbage collection :)
ConditionEntriesByTypeArray ConditionStore;
- ConditionReferenceContainer ConditionReferenceStore;
- ConditionEntriesByCreatureIdMap VehicleSpellConditionStore;
- ConditionEntriesByCreatureIdMap SpellClickEventConditionStore;
- ConditionEntriesByCreatureIdMap NpcVendorConditionContainerStore;
- SmartEventConditionContainer SmartEventConditionStore;
std::unordered_set<uint32> SpellsUsedInSpellClickConditions;
- ConditionEntriesByAreaTriggerIdMap AreaTriggerConditionContainerStore;
- ConditionEntriesByCreatureIdMap TrainerSpellConditionContainerStore;
- std::unordered_map<std::pair<uint32 /*object type*/, uint32 /*object id*/>, ConditionContainer> ObjectVisibilityConditionStore;
};
#define sConditionMgr ConditionMgr::instance()
+struct ConditionsReference
+{
+ bool Meets(WorldObject const* object) const
+ {
+ if (std::shared_ptr<std::vector<Condition>> conditions = Conditions.lock())
+ return sConditionMgr->IsObjectMeetToConditions(object, *conditions);
+ return true;
+ }
+
+ bool Meets(WorldObject const* object1, WorldObject const* object2) const
+ {
+ if (std::shared_ptr<std::vector<Condition>> conditions = Conditions.lock())
+ return sConditionMgr->IsObjectMeetToConditions(object1, object2, *conditions);
+ return true;
+ }
+
+ bool Meets(ConditionSourceInfo& sourceInfo) const
+ {
+ if (std::shared_ptr<std::vector<Condition>> conditions = Conditions.lock())
+ return sConditionMgr->IsObjectMeetToConditions(sourceInfo, *conditions);
+ return true;
+ }
+
+ bool IsEmpty() const
+ {
+ if (std::shared_ptr<std::vector<Condition>> conditions = Conditions.lock())
+ return conditions->empty();
+ return true;
+ }
+
+ std::weak_ptr<ConditionContainer> Conditions;
+};
+
#endif
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index aabde61d03d..5b06670dc50 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -13522,7 +13522,7 @@ void Player::PrepareGossipMenu(WorldObject* source, uint32 menuId, bool showQues
for (auto const& [_, gossipMenuItem] : menuItemBounds)
{
- if (!sConditionMgr->IsObjectMeetToConditions(this, source, gossipMenuItem.Conditions))
+ if (!gossipMenuItem.Conditions.Meets(this, source))
continue;
bool canTalk = true;
@@ -13848,7 +13848,7 @@ uint32 Player::GetGossipTextId(uint32 menuId, WorldObject* source)
if (!itr->second.TextID)
continue;
- if (sConditionMgr->IsObjectMeetToConditions(this, source, itr->second.Conditions))
+ if (itr->second.Conditions.Meets(this, source))
textId = itr->second.TextID;
}
@@ -13874,7 +13874,7 @@ uint32 Player::GetGossipMenuForSource(WorldObject* source)
for (GossipMenusContainer::const_iterator itr = menuBounds.first; itr != menuBounds.second; ++itr)
{
- if (!sConditionMgr->IsObjectMeetToConditions(this, source, itr->second.Conditions))
+ if (!itr->second.Conditions.Meets(this, source))
continue;
menuIdToShow = menuId;
@@ -24441,7 +24441,7 @@ void Player::UpdateVisibleGameobjectsOrSpellClicks()
auto clickBounds = sObjectMgr->GetSpellClickInfoMapBounds(obj->GetEntry());
for (auto const& clickPair : clickBounds)
{
- if (sConditionMgr->GetConditionsForSpellClickEvent(obj->GetEntry(), clickPair.second.spellId))
+ if (sConditionMgr->HasConditionsForSpellClickEvent(obj->GetEntry(), clickPair.second.spellId))
{
UF::ObjectData::Base objMask;
UF::UnitData::Base unitMask;
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index 78540a5c6eb..b040b78c18a 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -6921,7 +6921,7 @@ WorldSafeLocsEntry const* ObjectMgr::GetClosestGraveyardInZone(WorldLocation con
if (conditionObject)
{
- if (!sConditionMgr->IsObjectMeetToConditions(conditionSource, data.Conditions))
+ if (!data.Conditions.Meets(conditionSource))
continue;
if (int16(entry->Loc.GetMapId()) == mapEntry->ParentMapID && !conditionObject->GetPhaseShift().HasVisibleMapId(entry->Loc.GetMapId()))
@@ -6930,15 +6930,18 @@ WorldSafeLocsEntry const* ObjectMgr::GetClosestGraveyardInZone(WorldLocation con
else if (team != 0)
{
bool teamConditionMet = true;
- for (Condition const* cond : data.Conditions)
+ if (std::shared_ptr<std::vector<Condition>> conditions = data.Conditions.Conditions.lock())
{
- if (cond->ConditionType != CONDITION_TEAM)
- continue;
+ for (Condition const& cond : *conditions)
+ {
+ if (cond.ConditionType != CONDITION_TEAM)
+ continue;
- if (cond->ConditionValue1 == team)
- continue;
+ if (cond.ConditionValue1 == team)
+ continue;
- teamConditionMet = false;
+ teamConditionMet = false;
+ }
}
if (!teamConditionMet)
diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h
index bf90e20bb6a..deae3736ff6 100644
--- a/src/server/game/Globals/ObjectMgr.h
+++ b/src/server/game/Globals/ObjectMgr.h
@@ -755,14 +755,14 @@ struct GossipMenuItems
uint32 BoxBroadcastTextID;
Optional<int32> SpellID;
Optional<int32> OverrideIconID;
- ConditionContainer Conditions;
+ ConditionsReference Conditions;
};
struct GossipMenus
{
uint32 MenuID;
uint32 TextID;
- ConditionContainer Conditions;
+ ConditionsReference Conditions;
};
struct GossipMenuAddon
@@ -836,7 +836,7 @@ struct WorldSafeLocsEntry
struct GraveyardData
{
uint32 safeLocId;
- ConditionContainer Conditions;
+ ConditionsReference Conditions;
};
typedef std::multimap<uint32, GraveyardData> GraveyardContainer;
diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp
index 7f230a2bb8f..c49299bc39d 100644
--- a/src/server/game/Handlers/MiscHandler.cpp
+++ b/src/server/game/Handlers/MiscHandler.cpp
@@ -369,7 +369,7 @@ void WorldSession::HandleRequestCemeteryList(WorldPackets::Misc::RequestCemetery
for (auto it = range.first; it != range.second && graveyardIds.size() < 16; ++it) // client max
{
ConditionSourceInfo conditionSource(_player);
- if (!sConditionMgr->IsObjectMeetToConditions(conditionSource, it->second.Conditions))
+ if (!it->second.Conditions.Meets(conditionSource))
continue;
graveyardIds.push_back(it->first);
diff --git a/src/server/game/Loot/Loot.cpp b/src/server/game/Loot/Loot.cpp
index c19a2a1c36c..eb19f3eb42f 100644
--- a/src/server/game/Loot/Loot.cpp
+++ b/src/server/game/Loot/Loot.cpp
@@ -74,10 +74,10 @@ bool LootItem::AllowedForPlayer(Player const* player, Loot const* loot) const
}
bool LootItem::AllowedForPlayer(Player const* player, Loot const* loot, uint32 itemid, bool needs_quest, bool follow_loot_rules, bool strictUsabilityCheck,
- ConditionContainer const& conditions)
+ ConditionsReference const& conditions)
{
// DB conditions check
- if (!sConditionMgr->IsObjectMeetToConditions(player, conditions))
+ if (!conditions.Meets(player))
return false;
ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(itemid);
@@ -954,7 +954,7 @@ bool Loot::hasItemForAll() const
return true;
for (LootItem const& item : items)
- if (!item.is_looted && item.follow_loot_rules && !item.freeforall && item.conditions.empty())
+ if (!item.is_looted && item.follow_loot_rules && !item.freeforall && item.conditions.IsEmpty())
return true;
return false;
}
diff --git a/src/server/game/Loot/Loot.h b/src/server/game/Loot/Loot.h
index 33bee4568c8..0e703187a82 100644
--- a/src/server/game/Loot/Loot.h
+++ b/src/server/game/Loot/Loot.h
@@ -178,7 +178,7 @@ struct TC_GAME_API LootItem
uint32 LootListId;
ItemRandomProperties randomProperties;
ItemContext context;
- ConditionContainer conditions; // additional loot condition
+ ConditionsReference conditions; // additional loot condition
GuidSet allowedGUIDs;
ObjectGuid rollWinnerGUID; // Stores the guid of person who won loot, if his bags are full only he can see the item in loot list!
uint8 count : 8;
@@ -207,7 +207,7 @@ struct TC_GAME_API LootItem
// Basic checks for player/item compatibility - if false no chance to see the item in the loot - used only for loot generation
bool AllowedForPlayer(Player const* player, Loot const* loot) const;
static bool AllowedForPlayer(Player const* player, Loot const* loot, uint32 itemid, bool needs_quest, bool follow_loot_rules, bool strictUsabilityCheck,
- ConditionContainer const& conditions);
+ ConditionsReference const& conditions);
void AddAllowedLooter(Player const* player);
GuidSet const& GetAllowedLooters() const { return allowedGUIDs; }
bool HasAllowedLooter(ObjectGuid const& looter) const;
diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp
index 0954a3ec779..ffd4fecb892 100644
--- a/src/server/game/Loot/LootMgr.cpp
+++ b/src/server/game/Loot/LootMgr.cpp
@@ -100,7 +100,6 @@ class LootTemplate::LootGroup // A set of loot def
void CheckLootRefs(LootTemplateMap const& store, LootIdSet* ref_set) const;
LootStoreItemList* GetExplicitlyChancedItemList() { return &ExplicitlyChanced; }
LootStoreItemList* GetEqualChancedItemList() { return &EqualChanced; }
- void CopyConditions(ConditionContainer conditions);
private:
LootStoreItemList ExplicitlyChanced; // Entries with chances defined in DB
LootStoreItemList EqualChanced; // Zero chances - every entry takes the same chance
@@ -216,15 +215,6 @@ bool LootStore::HaveQuestLootForPlayer(uint32 loot_id, Player const* player) con
return false;
}
-void LootStore::ResetConditions()
-{
- for (LootTemplateMap::iterator itr = m_LootTemplates.begin(); itr != m_LootTemplates.end(); ++itr)
- {
- ConditionContainer empty;
- itr->second->CopyConditions(empty);
- }
-}
-
LootTemplate const* LootStore::GetLootFor(uint32 loot_id) const
{
LootTemplateMap::const_iterator tab = m_LootTemplates.find(loot_id);
@@ -452,15 +442,6 @@ bool LootTemplate::LootGroup::HasQuestDropForPlayer(Player const* player) const
return false;
}
-void LootTemplate::LootGroup::CopyConditions(ConditionContainer /*conditions*/)
-{
- for (LootStoreItemList::iterator i = ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
- (*i)->conditions.clear();
-
- for (LootStoreItemList::iterator i = EqualChanced.begin(); i != EqualChanced.end(); ++i)
- (*i)->conditions.clear();
-}
-
// Rolls an item from the group (if any takes its chance) and adds the item to the loot
void LootTemplate::LootGroup::Process(Loot& loot, uint16 lootMode, Player const* personalLooter /*= nullptr*/) const
{
@@ -557,16 +538,6 @@ void LootTemplate::AddEntry(LootStoreItem* item)
Entries.push_back(item);
}
-void LootTemplate::CopyConditions(ConditionContainer const& conditions)
-{
- for (LootStoreItemList::iterator i = Entries.begin(); i != Entries.end(); ++i)
- (*i)->conditions.clear();
-
- for (LootGroups::iterator i = Groups.begin(); i != Groups.end(); ++i)
- if (LootGroup* group = *i)
- group->CopyConditions(conditions);
-}
-
void LootTemplate::CopyConditions(LootItem* li) const
{
// Copies the conditions list from a template item to a LootItemData
@@ -879,21 +850,15 @@ void LootTemplate::CheckLootRefs(LootTemplateMap const& store, LootIdSet* ref_se
group->CheckLootRefs(store, ref_set);
}
-bool LootTemplate::addConditionItem(Condition* cond)
+bool LootTemplate::LinkConditions(ConditionId const& id, ConditionsReference reference)
{
- if (!cond || !cond->isLoaded())//should never happen, checked at loading
- {
- TC_LOG_ERROR("loot", "LootTemplate::addConditionItem: condition is null");
- return false;
- }
-
if (!Entries.empty())
{
- for (LootStoreItemList::iterator i = Entries.begin(); i != Entries.end(); ++i)
+ for (LootStoreItem* item : Entries)
{
- if ((*i)->itemid == uint32(cond->SourceEntry))
+ if (item->itemid == uint32(id.SourceEntry))
{
- (*i)->conditions.push_back(cond);
+ item->conditions = std::move(reference);
return true;
}
}
@@ -901,20 +866,19 @@ bool LootTemplate::addConditionItem(Condition* cond)
if (!Groups.empty())
{
- for (LootGroups::iterator groupItr = Groups.begin(); groupItr != Groups.end(); ++groupItr)
+ for (LootGroup* group : Groups)
{
- LootGroup* group = *groupItr;
if (!group)
continue;
LootStoreItemList* itemList = group->GetExplicitlyChancedItemList();
if (!itemList->empty())
{
- for (LootStoreItemList::iterator i = itemList->begin(); i != itemList->end(); ++i)
+ for (LootStoreItem* item : *itemList)
{
- if ((*i)->itemid == uint32(cond->SourceEntry))
+ if (item->itemid == uint32(id.SourceEntry))
{
- (*i)->conditions.push_back(cond);
+ item->conditions = std::move(reference);
return true;
}
}
@@ -923,11 +887,11 @@ bool LootTemplate::addConditionItem(Condition* cond)
itemList = group->GetEqualChancedItemList();
if (!itemList->empty())
{
- for (LootStoreItemList::iterator i = itemList->begin(); i != itemList->end(); ++i)
+ for (LootStoreItem* item : *itemList)
{
- if ((*i)->itemid == uint32(cond->SourceEntry))
+ if (item->itemid == uint32(id.SourceEntry))
{
- (*i)->conditions.push_back(cond);
+ item->conditions = std::move(reference);
return true;
}
}
diff --git a/src/server/game/Loot/LootMgr.h b/src/server/game/Loot/LootMgr.h
index c481f4009ea..3dcb2ee1ddc 100644
--- a/src/server/game/Loot/LootMgr.h
+++ b/src/server/game/Loot/LootMgr.h
@@ -46,7 +46,7 @@ struct TC_GAME_API LootStoreItem
uint8 groupid;
uint8 mincount; // mincount for drop items
uint8 maxcount; // max drop count for the item mincount or Ref multiplicator
- ConditionContainer conditions; // additional loot condition
+ ConditionsReference conditions; // additional loot condition
// Constructor
// displayid is filled in IsValid() which must be called after
@@ -85,7 +85,6 @@ class TC_GAME_API LootStore
bool HaveQuestLootForPlayer(uint32 loot_id, Player const* player) const;
LootTemplate const* GetLootFor(uint32 loot_id) const;
- void ResetConditions();
LootTemplate* GetLootForConditionFill(uint32 loot_id);
char const* GetName() const { return m_name; }
@@ -115,7 +114,6 @@ class TC_GAME_API LootTemplate
// Rolls for every item in the template and adds the rolled items the the loot
void Process(Loot& loot, bool rate, uint16 lootMode, uint8 groupId, Player const* personalLooter = nullptr) const;
void ProcessPersonalLoot(std::unordered_map<Player*, std::unique_ptr<Loot>>& personalLoot, bool rate, uint16 lootMode) const;
- void CopyConditions(ConditionContainer const& conditions);
void CopyConditions(LootItem* li) const;
// True if template includes at least 1 drop for the player
@@ -128,7 +126,7 @@ class TC_GAME_API LootTemplate
// Checks integrity of the template
void Verify(LootStore const& store, uint32 Id) const;
void CheckLootRefs(LootTemplateMap const& store, LootIdSet* ref_set) const;
- bool addConditionItem(Condition* cond);
+ bool LinkConditions(ConditionId const& id, ConditionsReference reference);
bool isReference(uint32 id);
private:
diff --git a/src/server/game/Phasing/PhaseShift.cpp b/src/server/game/Phasing/PhaseShift.cpp
index 0c11581b545..4ba7715c9b1 100644
--- a/src/server/game/Phasing/PhaseShift.cpp
+++ b/src/server/game/Phasing/PhaseShift.cpp
@@ -25,7 +25,7 @@ PhaseShift& PhaseShift::operator=(PhaseShift const& right) = default;
PhaseShift& PhaseShift::operator=(PhaseShift&& right) noexcept = default;
PhaseShift::~PhaseShift() = default;
-bool PhaseShift::AddPhase(uint32 phaseId, PhaseFlags flags, std::vector<Condition*> const* areaConditions, int32 references /*= 1*/)
+bool PhaseShift::AddPhase(uint32 phaseId, PhaseFlags flags, std::vector<Condition> const* areaConditions, int32 references /*= 1*/)
{
auto insertResult = Phases.emplace(phaseId, flags, nullptr);
ModifyPhasesReferences(insertResult.first, references);
diff --git a/src/server/game/Phasing/PhaseShift.h b/src/server/game/Phasing/PhaseShift.h
index 5c26f0c1a91..494ed428e26 100644
--- a/src/server/game/Phasing/PhaseShift.h
+++ b/src/server/game/Phasing/PhaseShift.h
@@ -56,13 +56,13 @@ class TC_GAME_API PhaseShift
public:
struct PhaseRef
{
- PhaseRef(uint32 id, PhaseFlags flags, std::vector<Condition*> const* conditions)
+ PhaseRef(uint32 id, PhaseFlags flags, std::vector<Condition> const* conditions)
: Id(id), Flags(flags), References(0), AreaConditions(conditions) { }
uint16 Id;
EnumFlag<PhaseFlags> Flags;
int32 References;
- std::vector<Condition*> const* AreaConditions;
+ std::vector<Condition> const* AreaConditions;
std::strong_ordering operator<=>(PhaseRef const& right) const { return Id <=> right.Id; }
bool operator==(PhaseRef const& right) const { return Id == right.Id; }
bool IsPersonal() const { return Flags.HasFlag(PhaseFlags::Personal); }
@@ -95,7 +95,7 @@ public:
ObjectGuid GetPersonalGuid() const { return PersonalGuid; }
- bool AddPhase(uint32 phaseId, PhaseFlags flags, std::vector<Condition*> const* areaConditions, int32 references = 1);
+ bool AddPhase(uint32 phaseId, PhaseFlags flags, std::vector<Condition> const* areaConditions, int32 references = 1);
EraseResult<PhaseContainer> RemovePhase(uint32 phaseId);
bool HasPhase(uint32 phaseId) const { return Phases.find(PhaseRef(phaseId, PhaseFlags::None, nullptr)) != Phases.end(); }
PhaseContainer const& GetPhases() const { return Phases; }
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp
index 1f1c8f68c95..cb541c2f84f 100644
--- a/src/server/game/Spells/Auras/SpellAuras.cpp
+++ b/src/server/game/Spells/Auras/SpellAuras.cpp
@@ -2521,7 +2521,7 @@ void UnitAura::FillTargetMap(std::unordered_map<Unit*, uint32>& targets, Unit* c
continue;
std::vector<WorldObject*> units;
- ConditionContainer* condList = spellEffectInfo.ImplicitTargetConditions;
+ ConditionContainer* condList = spellEffectInfo.ImplicitTargetConditions.get();
float radius = spellEffectInfo.CalcRadius(ref);
float extraSearchRadius = 0.0f;
@@ -2643,7 +2643,7 @@ void DynObjAura::FillTargetMap(std::unordered_map<Unit*, uint32>& targets, Unit*
selectionType = spellEffectInfo.TargetB.GetCheckType();
std::vector<Unit*> units;
- ConditionContainer* condList = spellEffectInfo.ImplicitTargetConditions;
+ ConditionContainer* condList = spellEffectInfo.ImplicitTargetConditions.get();
Trinity::WorldObjectSpellAreaTargetCheck check(radius, GetDynobjOwner(), dynObjOwnerCaster, dynObjOwnerCaster, m_spellInfo, selectionType, condList, TARGET_OBJECT_TYPE_UNIT);
Trinity::UnitListSearcher<Trinity::WorldObjectSpellAreaTargetCheck> searcher(GetDynobjOwner(), units, check);
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 65296e42063..2092fedc2d7 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -1128,7 +1128,7 @@ void Spell::SelectImplicitNearbyTargets(SpellEffectInfo const& spellEffectInfo,
break;
}
- ConditionContainer* condList = spellEffectInfo.ImplicitTargetConditions;
+ ConditionContainer* condList = spellEffectInfo.ImplicitTargetConditions.get();
// handle emergency case - try to use other provided targets if no conditions provided
if (targetType.GetCheckType() == TARGET_CHECK_ENTRY && (!condList || condList->empty()))
@@ -1312,7 +1312,7 @@ void Spell::SelectImplicitConeTargets(SpellEffectInfo const& spellEffectInfo, Sp
std::list<WorldObject*> targets;
SpellTargetObjectTypes objectType = targetType.GetObjectType();
SpellTargetCheckTypes selectionType = targetType.GetCheckType();
- ConditionContainer* condList = spellEffectInfo.ImplicitTargetConditions;
+ ConditionContainer* condList = spellEffectInfo.ImplicitTargetConditions.get();
float radius = spellEffectInfo.CalcRadius(m_caster, targetIndex) * m_spellValue->RadiusMod;
if (uint32 containerTypeMask = GetSearcherTypeMask(m_spellInfo, spellEffectInfo, objectType, condList))
@@ -1416,15 +1416,15 @@ void Spell::SelectImplicitAreaTargets(SpellEffectInfo const& spellEffectInfo, Sp
if (!m_caster->IsUnit() || !m_caster->ToUnit()->IsInRaidWith(targetedUnit))
targets.push_back(m_targets.GetUnitTarget());
else
- SearchAreaTargets(targets, spellEffectInfo, radius, targetedUnit, referer, targetType.GetObjectType(), targetType.GetCheckType(), spellEffectInfo.ImplicitTargetConditions);
+ SearchAreaTargets(targets, spellEffectInfo, radius, targetedUnit, referer, targetType.GetObjectType(), targetType.GetCheckType(), spellEffectInfo.ImplicitTargetConditions.get());
}
break;
case TARGET_UNIT_CASTER_AND_SUMMONS:
targets.push_back(m_caster);
- SearchAreaTargets(targets, spellEffectInfo, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(), spellEffectInfo.ImplicitTargetConditions);
+ SearchAreaTargets(targets, spellEffectInfo, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(), spellEffectInfo.ImplicitTargetConditions.get());
break;
default:
- SearchAreaTargets(targets, spellEffectInfo, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(), spellEffectInfo.ImplicitTargetConditions);
+ SearchAreaTargets(targets, spellEffectInfo, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(), spellEffectInfo.ImplicitTargetConditions.get());
break;
}
@@ -1871,7 +1871,7 @@ void Spell::SelectImplicitTrajTargets(SpellEffectInfo const& spellEffectInfo, Sp
float srcToDestDelta = m_targets.GetDstPos()->m_positionZ - srcPos.m_positionZ;
std::list<WorldObject*> targets;
- Trinity::WorldObjectSpellTrajTargetCheck check(dist2d, &srcPos, m_caster, m_spellInfo, targetType.GetCheckType(), spellEffectInfo.ImplicitTargetConditions, TARGET_OBJECT_TYPE_NONE);
+ Trinity::WorldObjectSpellTrajTargetCheck check(dist2d, &srcPos, m_caster, m_spellInfo, targetType.GetCheckType(), spellEffectInfo.ImplicitTargetConditions.get(), TARGET_OBJECT_TYPE_NONE);
Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellTrajTargetCheck> searcher(m_caster, targets, check, GRID_MAP_TYPE_MASK_ALL);
SearchTargets<Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellTrajTargetCheck> > (searcher, GRID_MAP_TYPE_MASK_ALL, m_caster, &srcPos, dist2d);
if (targets.empty())
@@ -1968,7 +1968,7 @@ void Spell::SelectImplicitLineTargets(SpellEffectInfo const& spellEffectInfo, Sp
return;
}
- ConditionContainer* condList = spellEffectInfo.ImplicitTargetConditions;
+ ConditionContainer* condList = spellEffectInfo.ImplicitTargetConditions.get();
float radius = spellEffectInfo.CalcRadius(m_caster, targetIndex) * m_spellValue->RadiusMod;
if (uint32 containerTypeMask = GetSearcherTypeMask(m_spellInfo, spellEffectInfo, objectType, condList))
@@ -2239,7 +2239,7 @@ void Spell::SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTar
WorldObject* chainSource = m_spellInfo->HasAttribute(SPELL_ATTR2_CHAIN_FROM_CASTER) ? m_caster : target;
std::list<WorldObject*> tempTargets;
- SearchAreaTargets(tempTargets, spellEffectInfo, searchRadius, chainSource, m_caster, objectType, selectType, spellEffectInfo.ImplicitTargetConditions);
+ SearchAreaTargets(tempTargets, spellEffectInfo, searchRadius, chainSource, m_caster, objectType, selectType, spellEffectInfo.ImplicitTargetConditions.get());
tempTargets.remove(target);
// remove targets which are always invalid for chain spells
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index b6ff92a0672..45dba1d63e6 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -4993,18 +4993,8 @@ void SpellInfo::_InitializeSpellPositivity()
void SpellInfo::_UnloadImplicitTargetConditionLists()
{
// find the same instances of ConditionList and delete them.
- for (SpellEffectInfo const& effect : _effects)
- {
- ConditionContainer* cur = effect.ImplicitTargetConditions;
- if (!cur)
- continue;
-
- for (size_t j = effect.EffectIndex; j < _effects.size(); ++j)
- if (_effects[j].ImplicitTargetConditions == cur)
- _effects[j].ImplicitTargetConditions = nullptr;
-
- delete cur;
- }
+ for (SpellEffectInfo& effect : _effects)
+ effect.ImplicitTargetConditions = nullptr;
}
bool SpellInfo::MeetsFutureSpellPlayerCondition(Player const* player) const
diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h
index de758946dd7..1c968c94bc3 100644
--- a/src/server/game/Spells/SpellInfo.h
+++ b/src/server/game/Spells/SpellInfo.h
@@ -237,7 +237,7 @@ public:
uint32 TriggerSpell;
flag128 SpellClassMask;
float BonusCoefficientFromAP;
- std::vector<Condition*>* ImplicitTargetConditions;
+ std::shared_ptr<std::vector<Condition>> ImplicitTargetConditions;
EnumFlag<SpellEffectAttributes> EffectAttributes;
// SpellScalingEntry
struct ScalingInfo
diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp
index 96de137197b..df1e28ffada 100644
--- a/src/server/scripts/Commands/cs_npc.cpp
+++ b/src/server/scripts/Commands/cs_npc.cpp
@@ -1225,7 +1225,7 @@ public:
{
handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_LABEL, "Standard items", loot->items.size());
for (LootItem const& item : loot->items)
- if (!item.is_looted && !item.freeforall && item.conditions.empty())
+ if (!item.is_looted && !item.freeforall && item.conditions.IsEmpty())
_ShowLootEntry(handler, item.itemid, item.count);
if (!loot->GetPlayerFFAItems().empty())