diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Conditions/ConditionMgr.cpp | 676 | ||||
-rw-r--r-- | src/server/game/Conditions/ConditionMgr.h | 89 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 8 | ||||
-rw-r--r-- | src/server/game/Globals/ObjectMgr.cpp | 17 | ||||
-rw-r--r-- | src/server/game/Globals/ObjectMgr.h | 6 | ||||
-rw-r--r-- | src/server/game/Handlers/MiscHandler.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Loot/Loot.cpp | 6 | ||||
-rw-r--r-- | src/server/game/Loot/Loot.h | 4 | ||||
-rw-r--r-- | src/server/game/Loot/LootMgr.cpp | 58 | ||||
-rw-r--r-- | src/server/game/Loot/LootMgr.h | 6 | ||||
-rw-r--r-- | src/server/game/Phasing/PhaseShift.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Phasing/PhaseShift.h | 6 | ||||
-rw-r--r-- | src/server/game/Spells/Auras/SpellAuras.cpp | 4 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 16 | ||||
-rw-r--r-- | src/server/game/Spells/SpellInfo.cpp | 14 | ||||
-rw-r--r-- | src/server/game/Spells/SpellInfo.h | 2 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_npc.cpp | 2 |
17 files changed, 369 insertions, 549 deletions
diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index f18af4a220b..9d11270d594 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 908f2c56863..63c6172a3db 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -14000,7 +14000,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; @@ -14326,7 +14326,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; } @@ -14352,7 +14352,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; @@ -25130,7 +25130,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 d04ff396c13..b61f8c7e4b5 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -6900,7 +6900,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())) @@ -6909,15 +6909,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 e685aa29982..48bd713ee0d 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 2cd94891236..050f205eb8c 100644 --- a/src/server/game/Loot/Loot.cpp +++ b/src/server/game/Loot/Loot.cpp @@ -75,10 +75,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); @@ -956,7 +956,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 0a57e11b575..7534b23c672 100644 --- a/src/server/game/Loot/Loot.h +++ b/src/server/game/Loot/Loot.h @@ -179,7 +179,7 @@ struct TC_GAME_API LootItem ItemRandomBonusListId randomBonusListId; std::vector<int32> BonusListIDs; 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; @@ -208,7 +208,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 992e75baca7..569e4c36c4e 100644 --- a/src/server/game/Loot/LootMgr.cpp +++ b/src/server/game/Loot/LootMgr.cpp @@ -101,7 +101,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 @@ -217,15 +216,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); @@ -453,15 +443,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 { @@ -558,16 +539,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 @@ -880,21 +851,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; } } @@ -902,20 +867,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; } } @@ -924,11 +888,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 2fe302740aa..6a10f273d72 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -2525,7 +2525,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; @@ -2647,7 +2647,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 f7d8ba69917..4873e420c23 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -1129,7 +1129,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())) @@ -1313,7 +1313,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)) @@ -1417,15 +1417,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; } @@ -1872,7 +1872,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()) @@ -1969,7 +1969,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)) @@ -2240,7 +2240,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 30c8c4957c9..5f6748e93e8 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -5059,18 +5059,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()) |