From 80936edeabe1676ab7ee14bc46da34491ce50c44 Mon Sep 17 00:00:00 2001 From: hondacrx Date: Tue, 6 Feb 2024 09:39:26 -0500 Subject: [PATCH] Core/Conditions: Refactor ConditionMgr internals to get rid of separate containers for some condition source types Port From (https://github.com/TrinityCore/TrinityCore/commit/0b5406dd882c6d96bc1be6fd0a78375c3b316415) --- Source/Framework/Constants/ConditionConst.cs | 3 + Source/Game/Chat/Commands/NPCCommands.cs | 2 +- Source/Game/Conditions/Condition.cs | 50 +- Source/Game/Conditions/ConditionManager.cs | 510 ++++++++----------- Source/Game/Entities/Creature/Gossip.cs | 4 +- Source/Game/Entities/Player/Player.Quest.cs | 3 +- Source/Game/Entities/Player/Player.cs | 8 +- Source/Game/Globals/ObjectManager.cs | 6 +- Source/Game/Handlers/CharacterHandler.cs | 2 +- Source/Game/Loot/Loot.cs | 8 +- Source/Game/Loot/LootManager.cs | 64 +-- Source/Game/Spells/SpellInfo.cs | 15 +- 12 files changed, 292 insertions(+), 383 deletions(-) diff --git a/Source/Framework/Constants/ConditionConst.cs b/Source/Framework/Constants/ConditionConst.cs index 013f440d3..e2c3a45c2 100644 --- a/Source/Framework/Constants/ConditionConst.cs +++ b/Source/Framework/Constants/ConditionConst.cs @@ -102,6 +102,9 @@ namespace Framework.Constants TrainerSpell = 31, ObjectIdVisibility = 32, SpawnGroup = 33, + + MaxDbAllowed, + ReferenceCondition = MaxDbAllowed, Max } diff --git a/Source/Game/Chat/Commands/NPCCommands.cs b/Source/Game/Chat/Commands/NPCCommands.cs index e9710b764..6e304ad5b 100644 --- a/Source/Game/Chat/Commands/NPCCommands.cs +++ b/Source/Game/Chat/Commands/NPCCommands.cs @@ -334,7 +334,7 @@ namespace Game.Chat { handler.SendSysMessage(CypherStrings.CommandNpcShowlootLabel, "Standard items", loot.items.Count); foreach (LootItem item in 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()) diff --git a/Source/Game/Conditions/Condition.cs b/Source/Game/Conditions/Condition.cs index ec36669df..c078f8f3f 100644 --- a/Source/Game/Conditions/Condition.cs +++ b/Source/Game/Conditions/Condition.cs @@ -619,8 +619,10 @@ namespace Game.Conditions { StringBuilder ss = new(); ss.AppendFormat("[Condition SourceType: {0}", SourceType); - if (SourceType < ConditionSourceType.Max) + if (SourceType < ConditionSourceType.MaxDbAllowed) ss.AppendFormat(" ({0})", Global.ConditionMgr.StaticSourceTypeData[(int)SourceType]); + else if (SourceType == ConditionSourceType.ReferenceCondition) + ss.Append(" (Reference)"); else ss.Append(" (Unknown)"); if (Global.ConditionMgr.CanHaveSourceGroupSet(SourceType)) @@ -659,6 +661,52 @@ namespace Game.Conditions public bool NegativeCondition; } + public struct ConditionId + { + public uint SourceGroup; + public int SourceEntry; + public uint SourceId; + + public ConditionId(uint sourceGroup, int sourceEntry, uint sourceId) + { + SourceGroup = sourceGroup; + SourceEntry = sourceEntry; + SourceId = sourceId; + } + + public override int GetHashCode() + { + return SourceGroup.GetHashCode() ^ SourceEntry.GetHashCode() ^ SourceId.GetHashCode(); + } + + public override bool Equals(object obj) + { + if (obj is ConditionId) + return (ConditionId)obj == this; + + return false; + } + + public static bool operator ==(ConditionId left, ConditionId right) + { + if (left.SourceGroup != right.SourceGroup) + return false; + + if (left.SourceEntry != right.SourceEntry) + return false; + + if (left.SourceId != right.SourceId) + return false; + + return true; + } + + public static bool operator !=(ConditionId left, ConditionId right) + { + return !(left == right); + } + } + public class ConditionSourceInfo { public ConditionSourceInfo(WorldObject target0, WorldObject target1 = null, WorldObject target2 = null) diff --git a/Source/Game/Conditions/ConditionManager.cs b/Source/Game/Conditions/ConditionManager.cs index 329e86380..d13aae2f0 100644 --- a/Source/Game/Conditions/ConditionManager.cs +++ b/Source/Game/Conditions/ConditionManager.cs @@ -41,7 +41,7 @@ namespace Game if (i.ReferenceId != 0) // handle reference { - var refe = conditionReferenceStorage.LookupByKey(i.ReferenceId); + var refe = ConditionStorage[ConditionSourceType.ReferenceCondition].LookupByKey(new ConditionId(i.ReferenceId, 0, 0)); Cypher.Assert(refe.Empty(), "ConditionMgr.GetSearcherTypeMaskForConditionList - incorrect reference"); elseGroupSearcherTypeMasks[i.ElseGroup] &= GetSearcherTypeMaskForConditionList(refe); } @@ -71,15 +71,13 @@ namespace Game if (condition.IsLoaded()) { //! Find ElseGroup in ElseGroupStore - //! If not found, add an entry in the store and set to true (placeholder) - if (!elseGroupStore.ContainsKey(condition.ElseGroup)) - elseGroupStore[condition.ElseGroup] = true; - else if (!elseGroupStore[condition.ElseGroup]) //! If another condition in this group was unmatched before this, don't bother checking (the group is false anyway) + var added = elseGroupStore.TryAdd(condition.ElseGroup, true); + if (!added) //! If another condition in this group was unmatched before this, don't bother checking (the group is false anyway) continue; if (condition.ReferenceId != 0)//handle reference { - var refe = conditionReferenceStorage.LookupByKey(condition.ReferenceId); + var refe = ConditionStorage[ConditionSourceType.ReferenceCondition].LookupByKey(new ConditionId(condition.ReferenceId, 0, 0)); if (!refe.Empty()) { if (!IsObjectMeetToConditionList(sourceInfo, refe)) @@ -152,7 +150,8 @@ namespace Game sourceType == ConditionSourceType.Graveyard || sourceType == ConditionSourceType.AreaTrigger || sourceType == ConditionSourceType.TrainerSpell || - sourceType == ConditionSourceType.ObjectIdVisibility; + sourceType == ConditionSourceType.ObjectIdVisibility || + sourceType == ConditionSourceType.ReferenceCondition; } public bool CanHaveSourceIdSet(ConditionSourceType sourceType) @@ -189,7 +188,7 @@ namespace Game { if (sourceType > ConditionSourceType.None && sourceType < ConditionSourceType.Max) { - var conditions = conditionStorage[sourceType].LookupByKey(entry); + var conditions = ConditionStorage[sourceType].LookupByKey(new ConditionId(0, (int)entry, 0)); if (!conditions.Empty()) { Log.outDebug(LogFilter.Condition, "GetConditionsForNotGroupedEntry: found conditions for type {0} and entry {1}", sourceType, entry); @@ -211,92 +210,75 @@ namespace Game ConditionSourceInfo conditionSource = new(map); return IsObjectMeetingNotGroupedConditions(sourceType, entry, conditionSource); } - + public bool HasConditionsForNotGroupedEntry(ConditionSourceType sourceType, uint entry) { if (sourceType > ConditionSourceType.None && sourceType < ConditionSourceType.Max) - if (conditionStorage[sourceType].ContainsKey(entry)) - return true; + return ConditionStorage[sourceType].ContainsKey(new ConditionId(0, (int)entry, 0)); return false; } public bool IsObjectMeetingSpellClickConditions(uint creatureId, uint spellId, WorldObject clicker, WorldObject target) { - var multiMap = spellClickEventConditionStorage.LookupByKey(creatureId); - if (multiMap != null) + var conditions = ConditionStorage[ConditionSourceType.SpellClickEvent].LookupByKey(new ConditionId(creatureId, (int)spellId, 0)); + if (!conditions.Empty()) { - var conditions = multiMap.LookupByKey(spellId); - if (!conditions.Empty()) - { - Log.outDebug(LogFilter.Condition, "GetConditionsForSpellClickEvent: found conditions for SpellClickEvent entry {0} spell {1}", creatureId, spellId); - ConditionSourceInfo sourceInfo = new(clicker, target); - return IsObjectMeetToConditions(sourceInfo, conditions); - } + Log.outDebug(LogFilter.Condition, "GetConditionsForSpellClickEvent: found conditions for SpellClickEvent entry {0} spell {1}", creatureId, spellId); + ConditionSourceInfo sourceInfo = new(clicker, target); + return IsObjectMeetToConditions(sourceInfo, conditions); + } return true; } - public List GetConditionsForSpellClickEvent(uint creatureId, uint spellId) + public bool HasConditionsForSpellClickEvent(uint creatureId, uint spellId) { - var multiMap = spellClickEventConditionStorage.LookupByKey(creatureId); - if (multiMap != null) + if (ConditionStorage[ConditionSourceType.SpellClickEvent].ContainsKey(new ConditionId(creatureId, (int)spellId, 0))) { - var conditions = multiMap.LookupByKey(spellId); - if (!conditions.Empty()) - { - Log.outDebug(LogFilter.Condition, "GetConditionsForSpellClickEvent: found conditions for SpellClickEvent entry {0} spell {1}", creatureId, spellId); - return conditions; - } + Log.outDebug(LogFilter.Condition, "GetConditionsForSpellClickEvent: found conditions for SpellClickEvent entry {0} spell {1}", creatureId, spellId); + return true; } - return null; + + return false; } public bool IsObjectMeetingVehicleSpellConditions(uint creatureId, uint spellId, Player player, Unit vehicle) { - var multiMap = vehicleSpellConditionStorage.LookupByKey(creatureId); - if (multiMap != null) + var conditions = ConditionStorage[ConditionSourceType.VehicleSpell].LookupByKey(new ConditionId(creatureId, (int)spellId, 0)); + if (conditions != null) { - var conditions = multiMap.LookupByKey(spellId); - if (!conditions.Empty()) - { - Log.outDebug(LogFilter.Condition, "GetConditionsForVehicleSpell: found conditions for Vehicle entry {0} spell {1}", creatureId, spellId); - ConditionSourceInfo sourceInfo = new(player, vehicle); - return IsObjectMeetToConditions(sourceInfo, conditions); - } + Log.outDebug(LogFilter.Condition, "GetConditionsForVehicleSpell: found conditions for Vehicle entry {0} spell {1}", creatureId, spellId); + ConditionSourceInfo sourceInfo = new(player, vehicle); + return IsObjectMeetToConditions(sourceInfo, conditions); } + return true; } public bool IsObjectMeetingSmartEventConditions(long entryOrGuid, uint eventId, SmartScriptType sourceType, Unit unit, WorldObject baseObject) { - var multiMap = smartEventConditionStorage.LookupByKey(Tuple.Create((int)entryOrGuid, (uint)sourceType)); - if (multiMap != null) + var conditions = ConditionStorage[ConditionSourceType.SmartEvent].LookupByKey(new ConditionId(eventId + 1, (int)entryOrGuid, (uint)sourceType)); + if (!conditions.Empty()) { - var conditions = multiMap.LookupByKey(eventId + 1); - if (!conditions.Empty()) - { - Log.outDebug(LogFilter.Condition, "GetConditionsForSmartEvent: found conditions for Smart Event entry or guid {0} eventId {1}", entryOrGuid, eventId); - ConditionSourceInfo sourceInfo = new(unit, baseObject); - return IsObjectMeetToConditions(sourceInfo, conditions); - } + Log.outDebug(LogFilter.Condition, "GetConditionsForSmartEvent: found conditions for Smart Event entry or guid {0} eventId {1}", entryOrGuid, eventId); + ConditionSourceInfo sourceInfo = new(unit, baseObject); + return IsObjectMeetToConditions(sourceInfo, conditions); } + return true; } public bool IsObjectMeetingVendorItemConditions(uint creatureId, uint itemId, Player player, Creature vendor) { - var multiMap = npcVendorConditionContainerStorage.LookupByKey(creatureId); - if (multiMap != null) + var conditions = ConditionStorage[ConditionSourceType.NpcVendor].LookupByKey(new ConditionId(creatureId, (int)itemId, 0)); + if (!conditions.Empty()) { - var conditions = multiMap.LookupByKey(itemId); - if (!conditions.Empty()) - { - Log.outDebug(LogFilter.Condition, "GetConditionsForNpcVendor: found conditions for creature entry {0} item {1}", creatureId, itemId); - ConditionSourceInfo sourceInfo = new(player, vendor); - return IsObjectMeetToConditions(sourceInfo, conditions); - } + Log.outDebug(LogFilter.Condition, "GetConditionsForNpcVendor: found conditions for creature entry {0} item {1}", creatureId, itemId); + ConditionSourceInfo sourceInfo = new(player, vendor); + return IsObjectMeetToConditions(sourceInfo, conditions); } + return true; } @@ -304,38 +286,35 @@ namespace Game { return spellsUsedInSpellClickConditions.Contains(spellId); } - + public List GetConditionsForAreaTrigger(uint areaTriggerId, bool isServerSide) { - return areaTriggerConditionContainerStorage.LookupByKey(Tuple.Create(areaTriggerId, isServerSide)); + return ConditionStorage[ConditionSourceType.AreaTrigger].LookupByKey(new ConditionId(areaTriggerId, isServerSide ? 1 : 0, 0)); } public bool IsObjectMeetingTrainerSpellConditions(uint trainerId, uint spellId, Player player) { - var multiMap = trainerSpellConditionContainerStorage.LookupByKey(trainerId); - if (multiMap != null) + var conditions = ConditionStorage[ConditionSourceType.NpcVendor].LookupByKey(new ConditionId(trainerId, (int)spellId, 0)); + if (!conditions.Empty()) { - var conditionList = multiMap.LookupByKey(spellId); - if (!conditionList.Empty()) - { - Log.outDebug(LogFilter.Condition, $"GetConditionsForTrainerSpell: found conditions for trainer id {trainerId} spell {spellId}"); - return IsObjectMeetToConditions(player, conditionList); - } + Log.outDebug(LogFilter.Condition, $"GetConditionsForTrainerSpell: found conditions for trainer id {trainerId} spell {spellId}"); + return IsObjectMeetToConditions(player, conditions); } + return true; } public bool IsObjectMeetingVisibilityByObjectIdConditions(uint objectType, uint entry, WorldObject seer) { - var conditions = objectVisibilityConditionStorage.LookupByKey((objectType, entry)); - if (conditions != null) + var conditions = ConditionStorage[ConditionSourceType.ObjectIdVisibility].LookupByKey(new ConditionId(objectType, (int)entry, 0)); + if (!conditions.Empty()) { Log.outDebug(LogFilter.Condition, $"IsObjectMeetingVisibilityByObjectIdConditions: found conditions for objectType {objectType} entry {entry}"); return IsObjectMeetToConditions(seer, conditions); } return true; } - + public void LoadConditions(bool isReload = false) { uint oldMSTime = Time.GetMSTime(); @@ -345,25 +324,6 @@ namespace Game //must clear all custom handled cases (groupped types) before reload if (isReload) { - Log.outInfo(LogFilter.Server, "Reseting Loot Conditions..."); - LootStorage.Creature.ResetConditions(); - LootStorage.Fishing.ResetConditions(); - LootStorage.Gameobject.ResetConditions(); - LootStorage.Items.ResetConditions(); - LootStorage.Mail.ResetConditions(); - LootStorage.Milling.ResetConditions(); - LootStorage.Pickpocketing.ResetConditions(); - LootStorage.Reference.ResetConditions(); - LootStorage.Skinning.ResetConditions(); - LootStorage.Disenchant.ResetConditions(); - LootStorage.Prospecting.ResetConditions(); - LootStorage.Spell.ResetConditions(); - - Log.outInfo(LogFilter.Server, "Re-Loading `gossip_menu` Table for Conditions!"); - Global.ObjectMgr.LoadGossipMenu(); - - Log.outInfo(LogFilter.Server, "Re-Loading `gossip_menu_option` Table for Conditions!"); - Global.ObjectMgr.LoadGossipMenuItems(); Global.SpellMgr.UnloadSpellInfoImplicitTargetConditionLists(); Global.ObjectMgr.UnloadPhaseConditions(); @@ -379,6 +339,7 @@ namespace Game } uint count = 0; + do { Condition cond = new(); @@ -410,6 +371,7 @@ namespace Game Log.outError(LogFilter.Sql, "Condition reference {1} is referencing self, skipped", iSourceTypeOrReferenceId); continue; } + cond.ReferenceId = (uint)Math.Abs(iConditionTypeOrReference); string rowType = "reference template"; @@ -426,8 +388,6 @@ namespace Game Log.outError(LogFilter.Sql, "Condition {0} {1} has useless data in value3 ({2})!", rowType, iSourceTypeOrReferenceId, cond.ConditionValue3); if (cond.NegativeCondition) Log.outError(LogFilter.Sql, "Condition {0} {1} has useless data in NegativeCondition ({2})!", rowType, iSourceTypeOrReferenceId, cond.NegativeCondition); - if (cond.SourceGroup != 0 && iSourceTypeOrReferenceId < 0) - Log.outError(LogFilter.Sql, "Condition {0} {1} has useless data in SourceGroup ({2})!", rowType, iSourceTypeOrReferenceId, cond.SourceGroup); if (cond.SourceEntry != 0 && iSourceTypeOrReferenceId < 0) Log.outError(LogFilter.Sql, "Condition {0} {1} has useless data in SourceEntry ({2})!", rowType, iSourceTypeOrReferenceId, cond.SourceEntry); } @@ -436,13 +396,17 @@ namespace Game if (iSourceTypeOrReferenceId < 0)//it is a reference template { - conditionReferenceStorage.Add((uint)Math.Abs(iSourceTypeOrReferenceId), cond);//add to reference storage - count++; - continue; - }//end of reference templates + if (cond.SourceGroup != 0) + Log.outError(LogFilter.Sql, $"Condition reference template {iSourceTypeOrReferenceId} has useless data in SourceGroup ({cond.SourceGroup})!"); + if (cond.SourceEntry != 0) + Log.outError(LogFilter.Sql, $"Condition reference template {iSourceTypeOrReferenceId} has useless data in SourceEntry ({cond.SourceEntry})!"); + if (cond.SourceId != 0) + Log.outError(LogFilter.Sql, $"Condition reference template {iSourceTypeOrReferenceId} has useless data in SourceId ({cond.SourceId})!"); - //if not a reference and SourceType is invalid, skip - if (iConditionTypeOrReference >= 0 && !IsSourceTypeValid(cond)) + cond.SourceType = ConditionSourceType.ReferenceCondition; + cond.SourceGroup = (uint)-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) @@ -469,197 +433,127 @@ namespace Game cond.ErrorTextId = 0; } - if (cond.SourceGroup != 0) - { - bool valid = false; - // handle grouped conditions - switch (cond.SourceType) - { - case ConditionSourceType.CreatureLootTemplate: - valid = AddToLootTemplate(cond, LootStorage.Creature.GetLootForConditionFill(cond.SourceGroup)); - break; - case ConditionSourceType.DisenchantLootTemplate: - valid = AddToLootTemplate(cond, LootStorage.Disenchant.GetLootForConditionFill(cond.SourceGroup)); - break; - case ConditionSourceType.FishingLootTemplate: - valid = AddToLootTemplate(cond, LootStorage.Fishing.GetLootForConditionFill(cond.SourceGroup)); - break; - case ConditionSourceType.GameobjectLootTemplate: - valid = AddToLootTemplate(cond, LootStorage.Gameobject.GetLootForConditionFill(cond.SourceGroup)); - break; - case ConditionSourceType.ItemLootTemplate: - valid = AddToLootTemplate(cond, LootStorage.Items.GetLootForConditionFill(cond.SourceGroup)); - break; - case ConditionSourceType.MailLootTemplate: - valid = AddToLootTemplate(cond, LootStorage.Mail.GetLootForConditionFill(cond.SourceGroup)); - break; - case ConditionSourceType.MillingLootTemplate: - valid = AddToLootTemplate(cond, LootStorage.Milling.GetLootForConditionFill(cond.SourceGroup)); - break; - case ConditionSourceType.PickpocketingLootTemplate: - valid = AddToLootTemplate(cond, LootStorage.Pickpocketing.GetLootForConditionFill(cond.SourceGroup)); - break; - case ConditionSourceType.ProspectingLootTemplate: - valid = AddToLootTemplate(cond, LootStorage.Prospecting.GetLootForConditionFill(cond.SourceGroup)); - break; - case ConditionSourceType.ReferenceLootTemplate: - valid = AddToLootTemplate(cond, LootStorage.Reference.GetLootForConditionFill(cond.SourceGroup)); - break; - case ConditionSourceType.SkinningLootTemplate: - valid = AddToLootTemplate(cond, LootStorage.Skinning.GetLootForConditionFill(cond.SourceGroup)); - break; - case ConditionSourceType.SpellLootTemplate: - valid = AddToLootTemplate(cond, LootStorage.Spell.GetLootForConditionFill(cond.SourceGroup)); - break; - case ConditionSourceType.GossipMenu: - valid = AddToGossipMenus(cond); - break; - case ConditionSourceType.GossipMenuOption: - valid = AddToGossipMenuItems(cond); - break; - case ConditionSourceType.SpellClickEvent: - { - if (!spellClickEventConditionStorage.ContainsKey(cond.SourceGroup)) - spellClickEventConditionStorage[cond.SourceGroup] = new MultiMap(); + var key = new ConditionId(cond.SourceGroup, cond.SourceEntry, cond.SourceId); + if (!ConditionStorage[cond.SourceType].ContainsKey(key)) + ConditionStorage[cond.SourceType][key] = new List(); - spellClickEventConditionStorage[cond.SourceGroup].Add((uint)cond.SourceEntry, cond); - if (cond.ConditionType == ConditionTypes.Aura) - spellsUsedInSpellClickConditions.Add(cond.ConditionValue1); - ++count; - continue; // do not add to m_AllocatedMemory to avoid double deleting - } - case ConditionSourceType.SpellImplicitTarget: - valid = AddToSpellImplicitTargetConditions(cond); - break; - case ConditionSourceType.VehicleSpell: - { - if (!vehicleSpellConditionStorage.ContainsKey(cond.SourceGroup)) - vehicleSpellConditionStorage[cond.SourceGroup] = new MultiMap(); - - vehicleSpellConditionStorage[cond.SourceGroup].Add((uint)cond.SourceEntry, cond); - ++count; - continue; // do not add to m_AllocatedMemory to avoid double deleting - } - case ConditionSourceType.SmartEvent: - { - //! TODO: PAIR_32 ? - var key = Tuple.Create(cond.SourceEntry, cond.SourceId); - if (!smartEventConditionStorage.ContainsKey(key)) - smartEventConditionStorage[key] = new MultiMap(); - - smartEventConditionStorage[key].Add(cond.SourceGroup, cond); - ++count; - continue; - } - case ConditionSourceType.NpcVendor: - { - if (!npcVendorConditionContainerStorage.ContainsKey(cond.SourceGroup)) - npcVendorConditionContainerStorage[cond.SourceGroup] = new MultiMap(); - - npcVendorConditionContainerStorage[cond.SourceGroup].Add((uint)cond.SourceEntry, cond); - ++count; - continue; - } - case ConditionSourceType.Phase: - valid = AddToPhases(cond); - break; - case ConditionSourceType.Graveyard: - valid = AddToGraveyardData(cond); - break; - case ConditionSourceType.AreaTrigger: - areaTriggerConditionContainerStorage.Add(Tuple.Create(cond.SourceGroup, cond.SourceEntry != 0), cond); - ++count; - continue; - case ConditionSourceType.TrainerSpell: - { - if (!trainerSpellConditionContainerStorage.ContainsKey(cond.SourceGroup)) - trainerSpellConditionContainerStorage[cond.SourceGroup] = new MultiMap(); - - trainerSpellConditionContainerStorage[cond.SourceGroup].Add((uint)cond.SourceEntry, cond); - ++count; - continue; - } - case ConditionSourceType.ObjectIdVisibility: - { - objectVisibilityConditionStorage.Add((cond.SourceGroup, (uint)cond.SourceEntry), cond); - valid = true; - ++count; - continue; - } - default: - break; - } - - if (!valid) - Log.outError(LogFilter.Sql, "{0} Not handled grouped condition.", cond.ToString()); - else - ++count; - - continue; - } - - //add new Condition to storage based on Type/Entry - if (cond.SourceType == ConditionSourceType.SpellClickEvent && cond.ConditionType == ConditionTypes.Aura) - spellsUsedInSpellClickConditions.Add(cond.ConditionValue1); - - conditionStorage[cond.SourceType].Add((uint)cond.SourceEntry, cond); + ConditionStorage[cond.SourceType][key].Add(cond); ++count; } while (result.NextRow()); + foreach (var (id, conditions) in ConditionStorage[ConditionSourceType.CreatureLootTemplate]) + AddToLootTemplate(id, conditions, LootStorage.Creature.GetLootForConditionFill(id.SourceGroup)); + + foreach (var (id, conditions) in ConditionStorage[ConditionSourceType.DisenchantLootTemplate]) + AddToLootTemplate(id, conditions, LootStorage.Disenchant.GetLootForConditionFill(id.SourceGroup)); + + foreach (var (id, conditions) in ConditionStorage[ConditionSourceType.FishingLootTemplate]) + AddToLootTemplate(id, conditions, LootStorage.Fishing.GetLootForConditionFill(id.SourceGroup)); + + foreach (var (id, conditions) in ConditionStorage[ConditionSourceType.GameobjectLootTemplate]) + AddToLootTemplate(id, conditions, LootStorage.Gameobject.GetLootForConditionFill(id.SourceGroup)); + + foreach (var (id, conditions) in ConditionStorage[ConditionSourceType.ItemLootTemplate]) + AddToLootTemplate(id, conditions, LootStorage.Items.GetLootForConditionFill(id.SourceGroup)); + + foreach (var (id, conditions) in ConditionStorage[ConditionSourceType.MailLootTemplate]) + AddToLootTemplate(id, conditions, LootStorage.Mail.GetLootForConditionFill(id.SourceGroup)); + + foreach (var (id, conditions) in ConditionStorage[ConditionSourceType.MillingLootTemplate]) + AddToLootTemplate(id, conditions, LootStorage.Milling.GetLootForConditionFill(id.SourceGroup)); + + foreach (var (id, conditions) in ConditionStorage[ConditionSourceType.PickpocketingLootTemplate]) + AddToLootTemplate(id, conditions, LootStorage.Pickpocketing.GetLootForConditionFill(id.SourceGroup)); + + foreach (var (id, conditions) in ConditionStorage[ConditionSourceType.ProspectingLootTemplate]) + AddToLootTemplate(id, conditions, LootStorage.Prospecting.GetLootForConditionFill(id.SourceGroup)); + + foreach (var (id, conditions) in ConditionStorage[ConditionSourceType.ReferenceLootTemplate]) + AddToLootTemplate(id, conditions, LootStorage.Reference.GetLootForConditionFill(id.SourceGroup)); + + foreach (var (id, conditions) in ConditionStorage[ConditionSourceType.SkinningLootTemplate]) + AddToLootTemplate(id, conditions, LootStorage.Skinning.GetLootForConditionFill(id.SourceGroup)); + + foreach (var (id, conditions) in ConditionStorage[ConditionSourceType.SpellLootTemplate]) + AddToLootTemplate(id, conditions, LootStorage.Spell.GetLootForConditionFill(id.SourceGroup)); + + foreach (var (id, conditions) in ConditionStorage[ConditionSourceType.GossipMenu]) + AddToGossipMenus(id, conditions); + + foreach (var (id, conditions) in ConditionStorage[ConditionSourceType.GossipMenuOption]) + AddToGossipMenuItems(id, conditions); + + spellsUsedInSpellClickConditions.Clear(); + foreach (var (id, conditions) in ConditionStorage[ConditionSourceType.SpellClickEvent]) + foreach (Condition condition in conditions) + if (condition.ConditionType == ConditionTypes.Aura) + spellsUsedInSpellClickConditions.Add(condition.ConditionValue1); + + foreach (var (id, conditions) in ConditionStorage[ConditionSourceType.SpellImplicitTarget]) + foreach (Condition condition in conditions) + AddToSpellImplicitTargetConditions(condition); + + foreach (var (id, conditions) in ConditionStorage[ConditionSourceType.Phase]) + AddToPhases(id, conditions); + + foreach (var (id, conditions) in ConditionStorage[ConditionSourceType.Graveyard]) + AddToGraveyardData(id, conditions); + Log.outInfo(LogFilter.ServerLoading, "Loaded {0} conditions in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime)); } - bool AddToLootTemplate(Condition cond, LootTemplate loot) + void AddToLootTemplate(ConditionId id, List conditions, LootTemplate loot) { if (loot == null) { - Log.outError(LogFilter.Sql, "{0} LootTemplate {1} not found.", cond.ToString(), cond.SourceGroup); - return false; + foreach (Condition condition in conditions) + Log.outError(LogFilter.Sql, $"{condition} LootTemplate {condition.SourceGroup} not found."); + return; } - if (loot.AddConditionItem(cond)) - return true; + if (loot.LinkConditions(id, new ConditionsReference(conditions))) + return; - Log.outError(LogFilter.Sql, "{0} Item {1} not found in LootTemplate {2}.", cond.ToString(), cond.SourceEntry, cond.SourceGroup); - return false; + foreach (Condition condition in conditions) + Log.outError(LogFilter.Sql, $"{condition} Item {condition.SourceEntry} not found in LootTemplate {condition.SourceGroup}."); } - bool AddToGossipMenus(Condition cond) + void AddToGossipMenus(ConditionId id, List conditions) { - var pMenuBounds = Global.ObjectMgr.GetGossipMenusMapBounds(cond.SourceGroup); + var pMenuBounds = Global.ObjectMgr.GetGossipMenusMapBounds(id.SourceGroup); if (!pMenuBounds.Empty()) { foreach (var menu in pMenuBounds) { - if (menu.MenuId == cond.SourceGroup && (menu.TextId == cond.SourceEntry || cond.SourceEntry == 0)) - menu.Conditions.Add(cond); + if (menu.MenuId == id.SourceGroup && (menu.TextId == id.SourceEntry || id.SourceEntry == 0)) + menu.Conditions = new(conditions); } - return true; + return; } - Log.outError(LogFilter.Sql, $"{cond} GossipMenu {cond.SourceGroup} not found."); - return false; + foreach (Condition condition in conditions) + Log.outError(LogFilter.Sql, $"{condition} GossipMenu {condition.SourceGroup} not found."); } - bool AddToGossipMenuItems(Condition cond) + void AddToGossipMenuItems(ConditionId id, List conditions) { - var pMenuItemBounds = Global.ObjectMgr.GetGossipMenuItemsMapBounds(cond.SourceGroup); + var pMenuItemBounds = Global.ObjectMgr.GetGossipMenuItemsMapBounds(id.SourceGroup); foreach (var gossipMenuItem in pMenuItemBounds) { - if (gossipMenuItem.MenuID == cond.SourceGroup && gossipMenuItem.OrderIndex == cond.SourceEntry) + if (gossipMenuItem.MenuID == id.SourceGroup && gossipMenuItem.OrderIndex == id.SourceEntry) { - gossipMenuItem.Conditions.Add(cond); - return true; + gossipMenuItem.Conditions = new(conditions); + return; } } - Log.outError(LogFilter.Sql, "{0} GossipMenuId {1} Item {2} not found.", cond.ToString(), cond.SourceGroup, cond.SourceEntry); - return false; + foreach (Condition condition in conditions) + Log.outError(LogFilter.Sql, $"{condition} GossipMenuId {condition.SourceGroup} Item {condition.SourceEntry} not found."); } - bool AddToSpellImplicitTargetConditions(Condition cond) + void AddToSpellImplicitTargetConditions(Condition cond) { Global.SpellMgr.ForEachSpellInfoDifficulty((uint)cond.SourceEntry, spellInfo => { @@ -705,9 +599,8 @@ namespace Game // build new shared mask with found effect uint sharedMask = (uint)(1 << (int)spellEffectInfo.EffectIndex); - List cmp = spellEffectInfo.ImplicitTargetConditions; for (uint effIndex = spellEffectInfo.EffectIndex + 1; effIndex < spellInfo.GetEffects().Count; ++effIndex) - if (spellInfo.GetEffect(effIndex).ImplicitTargetConditions == cmp) + if (spellInfo.GetEffect(effIndex).ImplicitTargetConditions == spellEffectInfo.ImplicitTargetConditions) sharedMask |= (uint)(1 << (int)effIndex); sharedMasks.Add(sharedMask); @@ -764,14 +657,13 @@ namespace Game } } }); - return true; } - bool AddToPhases(Condition cond) + void AddToPhases(ConditionId id, List conditions) { - if (cond.SourceEntry == 0) + if (id.SourceEntry == 0) { - PhaseInfoStruct phaseInfo = Global.ObjectMgr.GetPhaseInfo(cond.SourceGroup); + PhaseInfoStruct phaseInfo = Global.ObjectMgr.GetPhaseInfo(id.SourceGroup); if (phaseInfo != null) { bool found = false; @@ -782,9 +674,9 @@ namespace Game { foreach (PhaseAreaInfo phase in phases) { - if (phase.PhaseInfo.Id == cond.SourceGroup) + if (phase.PhaseInfo.Id == id.SourceGroup) { - phase.Conditions.Add(cond); + phase.Conditions.AddRange(conditions); found = true; } } @@ -792,39 +684,39 @@ namespace Game } if (found) - return true; + return; } } else { - var phases = Global.ObjectMgr.GetPhasesForArea((uint)cond.SourceEntry); + var phases = Global.ObjectMgr.GetPhasesForArea((uint)id.SourceEntry); foreach (PhaseAreaInfo phase in phases) { - if (phase.PhaseInfo.Id == cond.SourceGroup) + if (phase.PhaseInfo.Id == id.SourceGroup) { - phase.Conditions.Add(cond); - return true; + phase.Conditions.AddRange(conditions); + return; } } } - Log.outError(LogFilter.Sql, $"{cond} Area {cond.SourceEntry} does not have phase {cond.SourceGroup}."); - return false; + foreach (Condition condition in conditions) + Log.outError(LogFilter.Sql, $"{condition} Area {condition.SourceEntry} does not have phase {condition.SourceGroup}."); } - bool AddToGraveyardData(Condition cond) + void AddToGraveyardData(ConditionId id, List conditions) { - GraveyardData graveyard = Global.ObjectMgr.FindGraveyardData((uint)cond.SourceEntry, cond.SourceGroup); + GraveyardData graveyard = Global.ObjectMgr.FindGraveyardData((uint)id.SourceEntry, id.SourceGroup); if (graveyard != null) { - graveyard.Conditions.Add(cond); - return true; + graveyard.Conditions = new(conditions); + return; } - Log.outError(LogFilter.Sql, $"{cond}, Graveyard {cond.SourceEntry} does not have ghostzone {cond.SourceGroup}."); - return false; + foreach (Condition condition in conditions) + Log.outError(LogFilter.Sql, $"{condition}, Graveyard {condition.SourceEntry} does not have ghostzone {condition.SourceGroup}."); } - + bool IsSourceTypeValid(Condition cond) { switch (cond.SourceType) @@ -1206,7 +1098,7 @@ namespace Game Log.outError(LogFilter.Sql, $"{cond.ToString()} in `condition` table, unexpected SourceEntry value (expected 0 or 1), ignoring."); return false; } - if (Global.AreaTriggerDataStorage.GetAreaTriggerTemplate(new AreaTriggerId(cond.SourceGroup, cond.SourceEntry != 0)) == null) + if (Global.AreaTriggerDataStorage.GetAreaTriggerTemplate(new AreaTriggerId(cond.SourceGroup, cond.SourceEntry == 1)) == null) { Log.outError(LogFilter.Sql, $"{cond.ToString()} in `condition` table, does not exist in `areatrigger_template`, ignoring."); return false; @@ -1883,26 +1775,10 @@ namespace Game void Clean() { - conditionReferenceStorage.Clear(); + foreach (var (_, conditionsMap) in ConditionStorage) + conditionsMap.Clear(); - conditionStorage.Clear(); - for (ConditionSourceType i = 0; i < ConditionSourceType.Max; ++i) - conditionStorage[i] = new MultiMap();//add new empty list for SourceType - - vehicleSpellConditionStorage.Clear(); - - smartEventConditionStorage.Clear(); - - spellClickEventConditionStorage.Clear(); spellsUsedInSpellClickConditions.Clear(); - - npcVendorConditionContainerStorage.Clear(); - - areaTriggerConditionContainerStorage.Clear(); - - trainerSpellConditionContainerStorage.Clear(); - - objectVisibilityConditionStorage.Clear(); } static bool PlayerConditionCompare(int comparisonType, int value1, int value2) @@ -2619,7 +2495,7 @@ namespace Game case UnitConditionVariable.InCombat: return unit.IsInCombat() ? 1 : 0; case UnitConditionVariable.IsMoving: - return unit.HasUnitMovementFlag(MovementFlag.Forward | MovementFlag.Backward | MovementFlag.StrafeLeft | MovementFlag.StrafeRight) ? 1:0; + return unit.HasUnitMovementFlag(MovementFlag.Forward | MovementFlag.Backward | MovementFlag.StrafeLeft | MovementFlag.StrafeRight) ? 1 : 0; case UnitConditionVariable.IsCasting: case UnitConditionVariable.IsCastingSpell: // this is supposed to return spell id by client code but data always has 0 or 1 return unit.GetCurrentSpell(CurrentSpellTypes.Generic) != null ? 1 : 0; @@ -2635,7 +2511,7 @@ namespace Game return unit.GetExactDistSq(attacker) < distance * distance; }); case UnitConditionVariable.IsAttackingMe: - return (otherUnit != null && unit.GetTarget() == otherUnit.GetGUID()) ? 1:0; + return (otherUnit != null && unit.GetTarget() == otherUnit.GetGUID()) ? 1 : 0; case UnitConditionVariable.Range: return otherUnit != null ? (int)unit.GetExactDist(otherUnit) : 0; case UnitConditionVariable.InMeleeRange: @@ -2802,7 +2678,7 @@ namespace Game { if (condition.Variable[i] == 0) break; - + int unitValue = GetUnitConditionVariable(unit, otherUnit, (UnitConditionVariable)condition.Variable[i], condition.Value[i]); bool meets = false; switch ((UnitConditionOp)condition.Op[i]) @@ -2840,7 +2716,7 @@ namespace Game return !condition.GetFlags().HasFlag(UnitConditionFlags.LogicOr); } - + static int EvalSingleValue(ByteBuffer buffer, Map map) { WorldStateExpressionValueType valueType = (WorldStateExpressionValueType)buffer.ReadUInt8(); @@ -3024,16 +2900,8 @@ namespace Game return false; } - Dictionary> conditionStorage = new(); - MultiMap conditionReferenceStorage = new(); - Dictionary> vehicleSpellConditionStorage = new(); - Dictionary> spellClickEventConditionStorage = new(); + Dictionary>> ConditionStorage = new(); List spellsUsedInSpellClickConditions = new(); - Dictionary> npcVendorConditionContainerStorage = new(); - Dictionary, MultiMap> smartEventConditionStorage = new(); - MultiMap, Condition> areaTriggerConditionContainerStorage = new(); - Dictionary> trainerSpellConditionContainerStorage = new(); - MultiMap<(uint objectType, uint objectId), Condition> objectVisibilityConditionStorage = new(); public string[] StaticSourceTypeData = { @@ -3150,4 +3018,34 @@ namespace Game public bool HasConditionValue3; } } + + public struct ConditionsReference + { + public List Conditions = new(); + + public ConditionsReference(List conditions) + { + Conditions = conditions; + } + + public bool Meets(WorldObject obj) + { + return Global.ConditionMgr.IsObjectMeetToConditions(obj, Conditions); + } + + public bool Meets(WorldObject obj1, WorldObject obj2) + { + return Global.ConditionMgr.IsObjectMeetToConditions(obj1, obj2, Conditions); + } + + public bool Meets(ConditionSourceInfo sourceInfo) + { + return Global.ConditionMgr.IsObjectMeetToConditions(sourceInfo, Conditions); + } + + public bool IsEmpty() + { + return Conditions.Empty(); + } + } } diff --git a/Source/Game/Entities/Creature/Gossip.cs b/Source/Game/Entities/Creature/Gossip.cs index 75e69dc77..275e192b3 100644 --- a/Source/Game/Entities/Creature/Gossip.cs +++ b/Source/Game/Entities/Creature/Gossip.cs @@ -789,7 +789,7 @@ namespace Game.Misc public uint BoxBroadcastTextId; public int? SpellID; public int? OverrideIconID; - public List Conditions = new(); + public ConditionsReference Conditions; } public class GossipMenuAddon @@ -817,6 +817,6 @@ namespace Game.Misc { public uint MenuId; public uint TextId; - public List Conditions = new(); + public ConditionsReference Conditions; } } diff --git a/Source/Game/Entities/Player/Player.Quest.cs b/Source/Game/Entities/Player/Player.Quest.cs index 9fd1881f2..c1b88d138 100644 --- a/Source/Game/Entities/Player/Player.Quest.cs +++ b/Source/Game/Entities/Player/Player.Quest.cs @@ -3301,8 +3301,7 @@ namespace Game.Entities var clickBounds = Global.ObjectMgr.GetSpellClickInfoMapBounds(obj.GetEntry()); foreach (var spellClickInfo in clickBounds) { - List conds = Global.ConditionMgr.GetConditionsForSpellClickEvent(obj.GetEntry(), spellClickInfo.spellId); - if (conds != null) + if (Global.ConditionMgr.HasConditionsForSpellClickEvent(obj.GetEntry(), spellClickInfo.spellId)) { ObjectFieldData objMask = new(); UnitData unitMask = new(); diff --git a/Source/Game/Entities/Player/Player.cs b/Source/Game/Entities/Player/Player.cs index e93bf8ac6..f438ab9aa 100644 --- a/Source/Game/Entities/Player/Player.cs +++ b/Source/Game/Entities/Player/Player.cs @@ -2564,7 +2564,7 @@ namespace Game.Entities foreach (var gossipMenuItem in menuItemBounds) { - if (!ConditionMgr.IsObjectMeetToConditions(this, source, gossipMenuItem.Conditions)) + if (!gossipMenuItem.Conditions.Meets(this, source)) continue; bool canTalk = true; @@ -2889,7 +2889,7 @@ namespace Game.Entities if (menu.TextId == 0) continue; - if (ConditionMgr.IsObjectMeetToConditions(this, source, menu.Conditions)) + if (menu.Conditions.Meets(this, source)) textId = menu.TextId; } @@ -2913,9 +2913,9 @@ namespace Game.Entities { var menuBounds = ObjectMgr.GetGossipMenusMapBounds(menuId); - foreach (var itr in menuBounds) + foreach (var menu in menuBounds) { - if (!ConditionMgr.IsObjectMeetToConditions(this, source, itr.Conditions)) + if (!menu.Conditions.Meets(this, source)) continue; menuIdToShow = menuId; diff --git a/Source/Game/Globals/ObjectManager.cs b/Source/Game/Globals/ObjectManager.cs index ac75cfc38..e3e76870c 100644 --- a/Source/Game/Globals/ObjectManager.cs +++ b/Source/Game/Globals/ObjectManager.cs @@ -901,7 +901,7 @@ namespace Game if (conditionObject != null) { - if (!Global.ConditionMgr.IsObjectMeetToConditions(conditionSource, data.Conditions)) + if (!data.Conditions.Meets(conditionSource)) continue; if (entry.Loc.GetMapId() == mapEntry.ParentMapID && !conditionObject.GetPhaseShift().HasVisibleMapId(entry.Loc.GetMapId())) @@ -910,7 +910,7 @@ namespace Game else if (team != 0) { bool teamConditionMet = true; - foreach (Condition cond in data.Conditions) + foreach (Condition cond in data.Conditions.Conditions) { if (cond.ConditionType != ConditionTypes.Team) continue; @@ -11309,7 +11309,7 @@ namespace Game public class GraveyardData { public uint SafeLocId; - public List Conditions = new(); + public ConditionsReference Conditions; } public class QuestPOIBlobData diff --git a/Source/Game/Handlers/CharacterHandler.cs b/Source/Game/Handlers/CharacterHandler.cs index 6f50d52dc..ff40f2b46 100644 --- a/Source/Game/Handlers/CharacterHandler.cs +++ b/Source/Game/Handlers/CharacterHandler.cs @@ -2436,7 +2436,7 @@ namespace Game { var gYard = range[(int)i]; ConditionSourceInfo conditionSource = new(_player); - if (!Global.ConditionMgr.IsObjectMeetToConditions(conditionSource, gYard.Conditions)) + if (!gYard.Conditions.Meets(conditionSource)) continue; graveyardIds.Add(i); diff --git a/Source/Game/Loot/Loot.cs b/Source/Game/Loot/Loot.cs index b1c58b249..cbcd64309 100644 --- a/Source/Game/Loot/Loot.cs +++ b/Source/Game/Loot/Loot.cs @@ -42,10 +42,10 @@ namespace Game.Loots return AllowedForPlayer(player, loot, itemid, needs_quest, follow_loot_rules, false, conditions); } - public static bool AllowedForPlayer(Player player, Loot loot, uint itemid, bool needs_quest, bool follow_loot_rules, bool strictUsabilityCheck, List conditions) + public static bool AllowedForPlayer(Player player, Loot loot, uint itemid, bool needs_quest, bool follow_loot_rules, bool strictUsabilityCheck, ConditionsReference conditions) { // DB conditions check - if (!Global.ConditionMgr.IsObjectMeetToConditions(player, conditions)) + if (!conditions.Meets(player)) return false; ItemTemplate pProto = Global.ObjectMgr.GetItemTemplate(itemid); @@ -180,7 +180,7 @@ namespace Game.Loots public uint randomBonusListId; public List BonusListIDs = new(); public ItemContext context; - public List conditions = new(); // additional loot condition + public ConditionsReference conditions; // additional loot condition public List allowedGUIDs = new(); public ObjectGuid rollWinnerGUID; // Stores the guid of person who won loot, if his bags are full only he can see the item in loot list! public byte count; @@ -999,7 +999,7 @@ namespace Game.Loots return true; foreach (LootItem item in 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/Source/Game/Loot/LootManager.cs b/Source/Game/Loot/LootManager.cs index 0ca18fa56..ec32a4db7 100644 --- a/Source/Game/Loot/LootManager.cs +++ b/Source/Game/Loot/LootManager.cs @@ -490,7 +490,7 @@ namespace Game.Loots public byte groupid; public byte mincount; // mincount for drop items public byte maxcount; // max drop count for the item mincount or Ref multiplicator - public List conditions; // additional loot condition + public ConditionsReference conditions; // additional loot condition public LootStoreItem(uint _itemid, uint _reference, float _chance, bool _needs_quest, ushort _lootmode, byte _groupid, byte _mincount, byte _maxcount) { @@ -502,7 +502,6 @@ namespace Game.Loots groupid = _groupid; mincount = _mincount; maxcount = _maxcount; - conditions = new List(); } public bool Roll(bool rate) @@ -581,7 +580,7 @@ namespace Game.Loots } public class LootStore - { + { public LootStore(string name, string entryName, bool ratesAllowed = true) { m_name = name; @@ -614,11 +613,11 @@ namespace Game.Loots { // all still listed ids isn't referenced foreach (var id in lootIdSet) - Log.outError( LogFilter.Sql, "Table '{0}' entry {1} isn't {2} and not referenced from loot, and then useless.", GetName(), id, GetEntryName()); + Log.outError(LogFilter.Sql, "Table '{0}' entry {1} isn't {2} and not referenced from loot, and then useless.", GetName(), id, GetEntryName()); } public void ReportNonExistingId(uint lootId, uint ownerId) { - Log.outError( LogFilter.Sql, "Table '{0}' Entry {1} does not exist but it is used by {2} {3}", GetName(), lootId, GetEntryName(), ownerId); + Log.outError(LogFilter.Sql, "Table '{0}' Entry {1} does not exist but it is used by {2} {3}", GetName(), lootId, GetEntryName(), ownerId); } public bool HaveLootFor(uint loot_id) { return m_LootTemplates.LookupByKey(loot_id) != null; } @@ -650,14 +649,7 @@ namespace Game.Loots return tab; } - public void ResetConditions() - { - foreach (var pair in m_LootTemplates) - { - List empty = new(); - pair.Value.CopyConditions(empty); - } - } + public LootTemplate GetLootForConditionFill(uint loot_id) { var tab = m_LootTemplates.LookupByKey(loot_id); @@ -928,14 +920,6 @@ namespace Game.Loots return false; } - public void CopyConditions(List conditions) - { - foreach (var i in Entries) - i.conditions.Clear(); - - foreach (var group in Groups.Values) - group.CopyConditions(conditions); - } public void CopyConditions(LootItem li) { // Copies the conditions list from a template item to a LootItem @@ -1044,21 +1028,16 @@ namespace Game.Loots foreach (var group in Groups.Values) group.CheckLootRefs(store, ref_set); } - public bool AddConditionItem(Condition cond) - { - if (cond == null || !cond.IsLoaded())//should never happen, checked at loading - { - Log.outError(LogFilter.Loot, "LootTemplate.addConditionItem: condition is null"); - return false; - } + public bool LinkConditions(ConditionId id, ConditionsReference reference) + { if (!Entries.Empty()) { - foreach (var i in Entries) + foreach (var item in Entries) { - if (i.itemid == cond.SourceEntry) + if (item.itemid == id.SourceEntry) { - i.conditions.Add(cond); + item.conditions = reference; return true; } } @@ -1066,7 +1045,7 @@ namespace Game.Loots if (!Groups.Empty()) { - foreach (var group in Groups.Values) + foreach (var (_, group) in Groups) { if (group == null) continue; @@ -1074,11 +1053,11 @@ namespace Game.Loots LootStoreItemList itemList = group.GetExplicitlyChancedItemList(); if (!itemList.Empty()) { - foreach (var i in itemList) + foreach (var item in itemList) { - if (i.itemid == cond.SourceEntry) + if (item.itemid == id.SourceEntry) { - i.conditions.Add(cond); + item.conditions = reference; return true; } } @@ -1087,11 +1066,11 @@ namespace Game.Loots itemList = group.GetEqualChancedItemList(); if (!itemList.Empty()) { - foreach (var i in itemList) + foreach (var item in itemList) { - if (i.itemid == cond.SourceEntry) + if (item.itemid == id.SourceEntry) { - i.conditions.Add(cond); + item.conditions = reference; return true; } } @@ -1100,6 +1079,7 @@ namespace Game.Loots } return false; } + public bool IsReference(uint id) { foreach (var storeItem in Entries) @@ -1210,14 +1190,6 @@ namespace Game.Loots } public LootStoreItemList GetExplicitlyChancedItemList() { return ExplicitlyChanced; } public LootStoreItemList GetEqualChancedItemList() { return EqualChanced; } - public void CopyConditions(List conditions) - { - foreach (var i in ExplicitlyChanced) - i.conditions.Clear(); - - foreach (var i in EqualChanced) - i.conditions.Clear(); - } LootStoreItemList ExplicitlyChanced = new(); // Entries with chances defined in DB LootStoreItemList EqualChanced = new(); // Zero chances - every entry takes the same chance diff --git a/Source/Game/Spells/SpellInfo.cs b/Source/Game/Spells/SpellInfo.cs index 20f35077d..af854e6ac 100644 --- a/Source/Game/Spells/SpellInfo.cs +++ b/Source/Game/Spells/SpellInfo.cs @@ -3883,19 +3883,8 @@ namespace Game.Spells public void _UnloadImplicitTargetConditionLists() { // find the same instances of ConditionList and delete them. - foreach (var effectInfo in _effects) - { - var cur = effectInfo.ImplicitTargetConditions; - if (cur == null) - continue; - - for (int j = (int)effectInfo.EffectIndex; j < _effects.Count; ++j) - { - SpellEffectInfo eff = _effects[j]; - if (eff.ImplicitTargetConditions == cur) - eff.ImplicitTargetConditions = null; - } - } + foreach (SpellEffectInfo effect in _effects) + effect.ImplicitTargetConditions = null; } public bool MeetsFutureSpellPlayerCondition(Player player)