aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/server/game/Conditions/ConditionMgr.cpp369
-rw-r--r--src/server/game/DataStores/DB2Structure.h2
-rw-r--r--src/server/game/DataStores/DBCEnums.h19
3 files changed, 207 insertions, 183 deletions
diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp
index 99d55c535e2..0eca332b7dc 100644
--- a/src/server/game/Conditions/ConditionMgr.cpp
+++ b/src/server/game/Conditions/ConditionMgr.cpp
@@ -978,25 +978,23 @@ uint32 ConditionMgr::GetSearcherTypeMaskForConditionList(ConditionContainer cons
{
// 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);
// group not filled yet, fill with widest mask possible
- if (itr == elseGroupSearcherTypeMasks.end())
- elseGroupSearcherTypeMasks[i->ElseGroup] = GRID_MAP_TYPE_MASK_ALL;
+ auto itr = elseGroupSearcherTypeMasks.try_emplace(i->ElseGroup, GRID_MAP_TYPE_MASK_ALL).first;
// no point of checking anymore, empty mask
- else if (!itr->second)
+ if (!itr->second)
continue;
if (i->ReferenceId) // handle reference
{
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));
+ itr->second &= 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();
+ itr->second &= i->GetSearcherTypeMaskForCondition();
}
}
// object will match condition when one of the checks in ElseGroupStore is matching
@@ -1476,7 +1474,7 @@ void ConditionMgr::LoadConditions(bool isReload)
{
bool operator()(uint32 playerConditionId, std::vector<Condition> const& conditions, ConditionEntriesByTypeArray const& store) const
{
- return std::any_of(conditions.begin(), conditions.end(), [&](Condition const& condition)
+ return std::ranges::any_of(conditions, [&](Condition const& condition)
{
if (condition.ConditionType == CONDITION_PLAYER_CONDITION)
{
@@ -2771,32 +2769,42 @@ inline bool PlayerConditionCompare(int32 comparisonType, int32 value1, int32 val
return false;
}
-template<std::size_t N>
-inline bool PlayerConditionLogic(uint32 logic, std::array<bool, N>& results)
+template <std::size_t N>
+inline bool PlayerConditionLogic(uint32 logic, std::bitset<N>& results)
{
static_assert(N < 8, "Logic array size must be equal to or less than 8");
- for (std::size_t i = 0; i < results.size(); ++i)
- if ((logic >> (16 + i)) & 1)
- results[i] ^= true;
-
- bool result = results[0];
+ uint32 resultsMask = results.to_ulong() ^ (logic >> 16);
+ uint32 result = resultsMask & 1;
for (std::size_t i = 1; i < results.size(); ++i)
{
switch ((logic >> (2 * (i - 1))) & 3)
{
case 1:
- result = result && results[i];
+ result &= (resultsMask >> i) & 1;
break;
case 2:
- result = result || results[i];
+ result |= (resultsMask >> i) & 1;
break;
default:
break;
}
}
- return result;
+ return result != 0;
+}
+
+template <typename T, std::size_t N, typename... ExtraParams, Trinity::invocable_r<bool, Player const*, T, typename ExtraParams::value_type...> Predicate>
+inline static std::bitset<N> GetPlayerConditionSingleResult(Predicate predicate, Player const* player, std::array<T, N> const& conditions, ExtraParams const&... params)
+{
+ static_assert(((std::tuple_size_v<ExtraParams> == N) && ...));
+ std::bitset<N> results;
+
+ for (std::size_t i = 0; i < N; ++i)
+ if (predicate(player, conditions[i], params[i]...))
+ results[i] = true;
+
+ return results;
}
uint32 ConditionMgr::GetPlayerConditionLfgValue(Player const* player, PlayerConditionLfgStatus status)
@@ -2853,34 +2861,45 @@ bool ConditionMgr::IsPlayerMeetingCondition(Player const* player, uint32 conditi
return false;
if (PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(conditionId))
- return IsPlayerMeetingCondition(player, playerCondition);
+ return IsPlayerMeetingCondition(player, playerCondition) != playerCondition->GetFlags().HasFlag(PlayerConditionFlags::Invert);
return true;
}
bool ConditionMgr::IsPlayerMeetingCondition(Player const* player, PlayerConditionEntry const* condition)
{
+ if (condition->GetFlags().HasFlag(PlayerConditionFlags::Disabled))
+ return true;
+
+ if (condition->GetFlags().HasFlag(PlayerConditionFlags::IsAtMaxExpansionLevel))
+ {
+ uint8 level = condition->GetFlags().HasFlag(PlayerConditionFlags::UseEffectiveLevel) ? player->GetEffectiveLevel() : player->GetLevel();
+ if (level < GetMaxLevelForExpansion(sWorld->getIntConfig(CONFIG_EXPANSION)))
+ return false;
+ }
+
if (Optional<ContentTuningLevels> levels = sDB2Manager.GetContentTuningData(condition->ContentTuningID, player->m_playerData->CtrOptions->ConditionalFlags))
{
- uint8 minLevel = condition->Flags & 0x800 ? levels->MinLevelWithDelta : levels->MinLevel;
+ uint8 level = condition->GetFlags().HasFlag(PlayerConditionFlags::UseEffectiveLevel) ? player->GetEffectiveLevel() : player->GetLevel();
+ uint8 minLevel = condition->GetFlags().HasFlag(PlayerConditionFlags::IncludeLevelDelta) ? levels->MinLevelWithDelta : levels->MinLevel;
uint8 maxLevel = 0;
- if (!(condition->Flags & 0x20))
- maxLevel = condition->Flags & 0x800 ? levels->MaxLevelWithDelta : levels->MaxLevel;
+ if (!condition->GetFlags().HasFlag(PlayerConditionFlags::WithinOrAboveRecord))
+ maxLevel = condition->GetFlags().HasFlag(PlayerConditionFlags::IncludeLevelDelta) ? levels->MaxLevelWithDelta : levels->MaxLevel;
- if (condition->Flags & 0x80)
+ if (condition->GetFlags().HasFlag(PlayerConditionFlags::InvertContentTuning))
{
- if (minLevel && player->GetLevel() >= minLevel && (!maxLevel || player->GetLevel() <= maxLevel))
+ if (minLevel && level >= minLevel && (!maxLevel || level <= maxLevel))
return false;
- if (maxLevel && player->GetLevel() <= maxLevel && (!minLevel || player->GetLevel() >= minLevel))
+ if (maxLevel && level <= maxLevel && (!minLevel || level >= minLevel))
return false;
}
else
{
- if (minLevel && player->GetLevel() < minLevel)
+ if (minLevel && level < minLevel)
return false;
- if (maxLevel && player->GetLevel() > maxLevel)
+ if (maxLevel && level > maxLevel)
return false;
}
}
@@ -2899,7 +2918,7 @@ bool ConditionMgr::IsPlayerMeetingCondition(Player const* player, PlayerConditio
if (condition->PowerType != -1 && condition->PowerTypeComp)
{
- int32 requiredPowerValue = condition->Flags & 4 ? player->GetMaxPower(Powers(condition->PowerType)) : condition->PowerTypeValue;
+ int32 requiredPowerValue = condition->GetFlags().HasFlag(PlayerConditionFlags::ComparePowerToMax) ? player->GetMaxPower(Powers(condition->PowerType)) : condition->PowerTypeValue;
if (!PlayerConditionCompare(condition->PowerTypeComp, player->GetPower(Powers(condition->PowerType)), requiredPowerValue))
return false;
}
@@ -2916,18 +2935,16 @@ bool ConditionMgr::IsPlayerMeetingCondition(Player const* player, PlayerConditio
}
}
- if (condition->SkillID[0] || condition->SkillID[1] || condition->SkillID[2] || condition->SkillID[3])
+ if (std::ranges::any_of(condition->SkillID, [](uint32 skillId) { return skillId != 0; }))
{
- std::array<bool, std::tuple_size_v<decltype(condition->SkillID)>> results;
- results.fill(true);
- for (std::size_t i = 0; i < condition->SkillID.size(); ++i)
+ auto results = GetPlayerConditionSingleResult([](Player const* player, uint32 skillId, uint32 minSkill, uint32 maxSkill)
{
- if (condition->SkillID[i])
- {
- uint16 skillValue = player->GetSkillValue(condition->SkillID[i]);
- results[i] = skillValue != 0 && skillValue > condition->MinSkill[i] && skillValue < condition->MaxSkill[i];
- }
- }
+ if (!skillId)
+ return true;
+
+ uint16 skillValue = player->GetSkillValue(skillId);
+ return skillValue != 0 && skillValue > minSkill && skillValue < maxSkill;
+ }, player, condition->SkillID, condition->MinSkill, condition->MaxSkill);
if (!PlayerConditionLogic(condition->SkillLogic, results))
return false;
@@ -2944,7 +2961,7 @@ bool ConditionMgr::IsPlayerMeetingCondition(Player const* player, PlayerConditio
languageSkill = std::max<int32>(languageSkill, player->GetSkillValue(languageDesc.second.SkillId));
}
- if (condition->MinLanguage && languageSkill < condition->MinLanguage)
+ if (condition->MinLanguage && languageSkill < int32(condition->MinLanguage))
return false;
if (condition->MaxLanguage && languageSkill > condition->MaxLanguage)
@@ -2953,35 +2970,39 @@ bool ConditionMgr::IsPlayerMeetingCondition(Player const* player, PlayerConditio
if (condition->MinFactionID[0] || condition->MinFactionID[1] || condition->MinFactionID[2] || condition->MaxFactionID)
{
+ auto isMinFactionConditionSatisfied = [](Player const* player, uint32 factionId, uint8 minReputationRank)
+ {
+ if (!sFactionStore.HasRecord(factionId))
+ return true;
+
+ if (ReputationRank const* forcedRank = player->GetReputationMgr().GetForcedRankIfAny(factionId))
+ return *forcedRank >= ReputationRank(minReputationRank);
+
+ return player->GetReputationRank(factionId) >= ReputationRank(minReputationRank);
+ };
+
+ auto isMaxFactionConditionSatisfied = [](Player const* player, uint32 factionId, uint8 maxReputationRank)
+ {
+ if (!sFactionStore.HasRecord(factionId))
+ return true;
+
+ if (ReputationRank const* forcedRank = player->GetReputationMgr().GetForcedRankIfAny(factionId))
+ return *forcedRank <= ReputationRank(maxReputationRank);
+
+ return player->GetReputationRank(factionId) <= ReputationRank(maxReputationRank);
+ };
+
if (!condition->MinFactionID[0] && !condition->MinFactionID[1] && !condition->MinFactionID[2])
{
- if (ReputationRank const* forcedRank = player->GetReputationMgr().GetForcedRankIfAny(condition->MaxFactionID))
- {
- if (*forcedRank > ReputationRank(condition->MaxReputation))
- return false;
- }
- else if (sFactionStore.HasRecord(condition->MaxReputation) && player->GetReputationRank(condition->MaxFactionID) > ReputationRank(condition->MaxReputation))
+ if (!isMaxFactionConditionSatisfied(player, condition->MaxFactionID, condition->MaxReputation))
return false;
}
else
{
- std::array<bool, std::tuple_size_v<decltype(condition->MinFactionID)> + 1> results;
- results.fill(true);
- for (std::size_t i = 0; i < condition->MinFactionID.size(); ++i)
- {
- if (sFactionStore.HasRecord(condition->MinFactionID[i]))
- {
- if (ReputationRank const* forcedRank = player->GetReputationMgr().GetForcedRankIfAny(condition->MinFactionID[i]))
- results[i] = *forcedRank >= ReputationRank(condition->MinReputation[i]);
- else
- results[i] = player->GetReputationRank(condition->MinFactionID[i]) >= ReputationRank(condition->MinReputation[i]);
- }
- }
-
- if (ReputationRank const* forcedRank = player->GetReputationMgr().GetForcedRankIfAny(condition->MaxFactionID))
- results[3] = *forcedRank <= ReputationRank(condition->MaxReputation);
- else if (sFactionStore.HasRecord(condition->MaxReputation))
- results[3] = player->GetReputationRank(condition->MaxFactionID) <= ReputationRank(condition->MaxReputation);
+ auto minFactionResults = GetPlayerConditionSingleResult(isMinFactionConditionSatisfied, player, condition->MinFactionID, condition->MinReputation);
+ std::bitset<minFactionResults.size() + 1> results(minFactionResults.to_ulong());
+ if (isMaxFactionConditionSatisfied(player, condition->MaxFactionID, condition->MaxReputation))
+ results[3] = true;
if (!PlayerConditionLogic(condition->ReputationLogic, results))
return false;
@@ -3051,10 +3072,10 @@ bool ConditionMgr::IsPlayerMeetingCondition(Player const* player, PlayerConditio
if (condition->PrevQuestID[0])
{
- std::array<bool, std::tuple_size_v<decltype(condition->PrevQuestID)>> results;
- results.fill(true);
- for (std::size_t i = 0; i < condition->PrevQuestID.size(); ++i)
- results[i] = player->IsQuestCompletedBitSet(condition->PrevQuestID[i]);
+ auto results = GetPlayerConditionSingleResult([](Player const* player, uint32 questId)
+ {
+ return !questId || player->IsQuestCompletedBitSet(questId);
+ }, player, condition->PrevQuestID);
if (!PlayerConditionLogic(condition->PrevQuestLogic, results))
return false;
@@ -3062,11 +3083,10 @@ bool ConditionMgr::IsPlayerMeetingCondition(Player const* player, PlayerConditio
if (condition->CurrQuestID[0])
{
- std::array<bool, std::tuple_size_v<decltype(condition->CurrQuestID)>> results;
- results.fill(true);
- for (std::size_t i = 0; i < condition->CurrQuestID.size(); ++i)
- if (condition->CurrQuestID[i])
- results[i] = player->FindQuestSlot(condition->CurrQuestID[i]) != MAX_QUEST_LOG_SIZE;
+ auto results = GetPlayerConditionSingleResult([](Player const* player, uint32 questId)
+ {
+ return !questId || player->FindQuestSlot(questId) != MAX_QUEST_LOG_SIZE;
+ }, player, condition->CurrQuestID);
if (!PlayerConditionLogic(condition->CurrQuestLogic, results))
return false;
@@ -3074,11 +3094,10 @@ bool ConditionMgr::IsPlayerMeetingCondition(Player const* player, PlayerConditio
if (condition->CurrentCompletedQuestID[0])
{
- std::array<bool, std::tuple_size_v<decltype(condition->CurrentCompletedQuestID)>> results;
- results.fill(true);
- for (std::size_t i = 0; i < condition->CurrentCompletedQuestID.size(); ++i)
- if (condition->CurrentCompletedQuestID[i])
- results[i] = player->GetQuestStatus(condition->CurrentCompletedQuestID[i]) == QUEST_STATUS_COMPLETE;
+ auto results = GetPlayerConditionSingleResult([](Player const* player, uint32 questId)
+ {
+ return !questId || player->GetQuestStatus(questId) == QUEST_STATUS_COMPLETE;
+ }, player, condition->CurrentCompletedQuestID);
if (!PlayerConditionLogic(condition->CurrentCompletedQuestLogic, results))
return false;
@@ -3086,11 +3105,10 @@ bool ConditionMgr::IsPlayerMeetingCondition(Player const* player, PlayerConditio
if (condition->SpellID[0])
{
- std::array<bool, std::tuple_size_v<decltype(condition->SpellID)>> results;
- results.fill(true);
- for (std::size_t i = 0; i < condition->SpellID.size(); ++i)
- if (condition->SpellID[i])
- results[i] = player->HasSpell(condition->SpellID[i]);
+ auto results = GetPlayerConditionSingleResult([](Player const* player, uint32 spellId)
+ {
+ return !spellId || player->HasSpell(spellId);
+ }, player, condition->SpellID);
if (!PlayerConditionLogic(condition->SpellLogic, results))
return false;
@@ -3098,35 +3116,38 @@ bool ConditionMgr::IsPlayerMeetingCondition(Player const* player, PlayerConditio
if (condition->ItemID[0])
{
- std::array<bool, std::tuple_size_v<decltype(condition->ItemID)>> results;
- results.fill(true);
- for (std::size_t i = 0; i < condition->ItemID.size(); ++i)
+ auto results = GetPlayerConditionSingleResult([itemFlags = condition->ItemFlags](Player const* player, uint32 itemId, uint32 itemCount)
{
- if (condition->ItemID[i])
- {
- EnumFlag<ItemSearchLocation> where = ItemSearchLocation::Equipment;
- if ((condition->ItemFlags & 1) != 0) // include banks
- where |= ItemSearchLocation::Bank | ItemSearchLocation::ReagentBank | ItemSearchLocation::AccountBank;
- if ((condition->ItemFlags & 2) == 0) // ignore inventory
- where |= ItemSearchLocation::Inventory;
+ if (!itemId)
+ return true;
- uint32 foundCount = 0;
- results[i] = !player->ForEachItem(where, [&](Item const* item)
+ EnumFlag<ItemSearchLocation> where = ItemSearchLocation::Equipment;
+ if ((itemFlags & 1) != 0) // include banks
+ where |= ItemSearchLocation::Bank | ItemSearchLocation::ReagentBank | ItemSearchLocation::AccountBank;
+ if ((itemFlags & 2) == 0) // ignore inventory
+ where |= ItemSearchLocation::Inventory;
+
+ uint32 foundCount = 0;
+ bool foundItemCount = !player->ForEachItem(where, [&](Item const* item)
+ {
+ if (item->GetEntry() == uint32(itemId))
{
- if (item->GetEntry() == uint32(condition->ItemID[i]))
- {
- foundCount += item->GetCount();
- if (foundCount >= condition->ItemCount[i])
- return ItemSearchCallbackResult::Stop;
- }
+ foundCount += item->GetCount();
+ if (foundCount >= itemCount)
+ return ItemSearchCallbackResult::Stop;
+ }
- return ItemSearchCallbackResult::Continue;
- });
+ return ItemSearchCallbackResult::Continue;
+ });
- if (!results[i] && condition->ItemCount[i] == 1 && sDB2Manager.IsToyItem(condition->ItemID[i]))
- results[i] = player->GetSession()->GetCollectionMgr()->HasToy(condition->ItemID[i]);
- }
- }
+ if (foundItemCount)
+ return true;
+
+ if (itemCount == 1 && sDB2Manager.IsToyItem(itemId) && player->GetSession()->GetCollectionMgr()->HasToy(itemId))
+ return true;
+
+ return false;
+ }, player, condition->ItemID, condition->ItemCount);
if (!PlayerConditionLogic(condition->ItemLogic, results))
return false;
@@ -3134,11 +3155,10 @@ bool ConditionMgr::IsPlayerMeetingCondition(Player const* player, PlayerConditio
if (condition->CurrencyID[0])
{
- std::array<bool, std::tuple_size_v<decltype(condition->CurrencyID)>> results;
- results.fill(true);
- for (std::size_t i = 0; i < condition->CurrencyID.size(); ++i)
- if (condition->CurrencyID[i])
- results[i] = player->GetCurrencyQuantity(condition->CurrencyID[i]) >= condition->CurrencyCount[i];
+ auto results = GetPlayerConditionSingleResult([](Player const* player, uint32 currencyId, uint32 count)
+ {
+ return !currencyId || player->GetCurrencyQuantity(currencyId) >= count;
+ }, player, condition->CurrencyID, condition->CurrencyCount);
if (!PlayerConditionLogic(condition->CurrencyLogic, results))
return false;
@@ -3154,18 +3174,16 @@ bool ConditionMgr::IsPlayerMeetingCondition(Player const* player, PlayerConditio
if (condition->AuraSpellID[0])
{
- std::array<bool, std::tuple_size_v<decltype(condition->AuraSpellID)>> results;
- results.fill(true);
- for (std::size_t i = 0; i < condition->AuraSpellID.size(); ++i)
+ auto results = GetPlayerConditionSingleResult([](Player const* player, uint32 spellId, uint32 count)
{
- if (condition->AuraSpellID[i])
- {
- if (condition->AuraStacks[i])
- results[i] = player->GetAuraCount(condition->AuraSpellID[i]) >= condition->AuraStacks[i];
- else
- results[i] = player->HasAura(condition->AuraSpellID[i]);
- }
- }
+ if (!spellId)
+ return true;
+
+ if (count)
+ return player->GetAuraCount(spellId) >= count;
+
+ return player->HasAura(spellId);
+ }, player, condition->AuraSpellID, condition->AuraStacks);
if (!PlayerConditionLogic(condition->AuraSpellLogic, results))
return false;
@@ -3204,17 +3222,15 @@ bool ConditionMgr::IsPlayerMeetingCondition(Player const* player, PlayerConditio
if (condition->Achievement[0])
{
- std::array<bool, std::tuple_size_v<decltype(condition->Achievement)>> results;
- results.fill(true);
- for (std::size_t i = 0; i < condition->Achievement.size(); ++i)
+ auto results = GetPlayerConditionSingleResult([flags = condition->GetFlags()](Player const* player, uint32 achievementId)
{
- if (condition->Achievement[i])
- {
- // if (condition->Flags & 2) { any character on account completed it } else { current character only }
- // TODO: part of accountwide achievements
- results[i] = player->HasAchieved(condition->Achievement[i]);
- }
- }
+ if (!achievementId)
+ return true;
+ (void)flags;
+ // if (flags.HasFlag(PlayerConditionFlags::CheckAchievementsOnAllChars)) { any character on account completed it } else { current character only }
+ // TODO: part of accountwide achievements
+ return player->HasAchieved(achievementId);
+ }, player, condition->Achievement);
if (!PlayerConditionLogic(condition->AchievementLogic, results))
return false;
@@ -3222,13 +3238,10 @@ bool ConditionMgr::IsPlayerMeetingCondition(Player const* player, PlayerConditio
if (condition->LfgStatus[0])
{
- std::array<bool, std::tuple_size_v<decltype(condition->LfgStatus)>> results;
- results.fill(true);
- for (std::size_t i = 0; i < condition->LfgStatus.size(); ++i)
- if (condition->LfgStatus[i])
- results[i] = PlayerConditionCompare(condition->LfgCompare[i],
- GetPlayerConditionLfgValue(player, PlayerConditionLfgStatus(condition->LfgStatus[i])),
- condition->LfgValue[i]);
+ auto results = GetPlayerConditionSingleResult([](Player const* player, uint8 status, uint8 compare, uint32 value)
+ {
+ return !status || PlayerConditionCompare(compare, GetPlayerConditionLfgValue(player, PlayerConditionLfgStatus(status)), value);
+ }, player, condition->LfgStatus, condition->LfgCompare, condition->LfgValue);
if (!PlayerConditionLogic(condition->LfgLogic, results))
return false;
@@ -3236,11 +3249,10 @@ bool ConditionMgr::IsPlayerMeetingCondition(Player const* player, PlayerConditio
if (condition->AreaID[0])
{
- std::array<bool, std::tuple_size_v<decltype(condition->AreaID)>> results;
- results.fill(true);
- for (std::size_t i = 0; i < condition->AreaID.size(); ++i)
- if (condition->AreaID[i])
- results[i] = DB2Manager::IsInArea(player->GetAreaId(), condition->AreaID[i]);
+ auto results = GetPlayerConditionSingleResult([](Player const* player, uint32 areaId)
+ {
+ return !areaId || DB2Manager::IsInArea(player->GetAreaId(), areaId);
+ }, player, condition->AreaID);
if (!PlayerConditionLogic(condition->AreaLogic, results))
return false;
@@ -3267,20 +3279,17 @@ bool ConditionMgr::IsPlayerMeetingCondition(Player const* player, PlayerConditio
uint16 questSlot = player->FindQuestSlot(condition->QuestKillID);
if (quest && player->GetQuestStatus(condition->QuestKillID) != QUEST_STATUS_COMPLETE && questSlot < MAX_QUEST_LOG_SIZE)
{
- std::array<bool, std::tuple_size_v<decltype(condition->QuestKillMonster)>> results;
- results.fill(true);
- for (std::size_t i = 0; i < condition->QuestKillMonster.size(); ++i)
+ auto results = GetPlayerConditionSingleResult([questSlot, quest](Player const* player, uint32 creatureId)
{
- if (condition->QuestKillMonster[i])
+ if (!creatureId)
+ return true;
+
+ auto objectiveItr = std::ranges::find_if(quest->GetObjectives(), [creatureId](QuestObjective const& objective) -> bool
{
- auto objectiveItr = std::find_if(quest->GetObjectives().begin(), quest->GetObjectives().end(), [condition, i](QuestObjective const& objective) -> bool
- {
- return objective.Type == QUEST_OBJECTIVE_MONSTER && uint32(objective.ObjectID) == condition->QuestKillMonster[i];
- });
- if (objectiveItr != quest->GetObjectives().end())
- results[i] = player->GetQuestSlotObjectiveData(questSlot, *objectiveItr) >= objectiveItr->Amount;
- }
- }
+ return objective.Type == QUEST_OBJECTIVE_MONSTER && uint32(objective.ObjectID) == creatureId;
+ });
+ return objectiveItr == quest->GetObjectives().end() || player->GetQuestSlotObjectiveData(questSlot, *objectiveItr) >= objectiveItr->Amount;
+ }, player, condition->QuestKillMonster);
if (!PlayerConditionLogic(condition->QuestKillLogic, results))
return false;
@@ -3299,7 +3308,7 @@ bool ConditionMgr::IsPlayerMeetingCondition(Player const* player, PlayerConditio
if (condition->MaxAvgEquippedItemLevel && uint32(std::floor(player->m_playerData->AvgItemLevel[1])) > condition->MaxAvgEquippedItemLevel)
return false;
- if (condition->ModifierTreeID && !player->ModifierTreeSatisfied(condition->ModifierTreeID))
+ if (condition->ModifierTreeID && player->ModifierTreeSatisfied(condition->ModifierTreeID) == condition->GetFlags().HasFlag(PlayerConditionFlags::InvertModifierTree))
return false;
if (condition->CovenantID && player->m_playerData->CovenantID != condition->CovenantID)
@@ -3307,39 +3316,33 @@ bool ConditionMgr::IsPlayerMeetingCondition(Player const* player, PlayerConditio
if (std::ranges::any_of(condition->TraitNodeEntryID, [](int32 traitNodeEntryId) { return traitNodeEntryId != 0; }))
{
- auto getTraitNodeEntryRank = [player](int32 traitNodeEntryId) -> Optional<uint16>
+ auto results = GetPlayerConditionSingleResult([](Player const* player, int32 traitNodeEntryId, uint16 minRank, uint16 maxRank)
{
- for (auto const& [_, traitConfig] : player->m_activePlayerData->TraitConfigs)
+ if (!traitNodeEntryId)
+ return true;
+
+ Optional<uint16> rank = [&]() -> Optional<uint16>
{
- if (TraitConfigType(*traitConfig.value.Type) == TraitConfigType::Combat)
+ for (auto const& [_, traitConfig] : player->m_activePlayerData->TraitConfigs)
{
- if (int32(*player->m_activePlayerData->ActiveCombatTraitConfigID) != *traitConfig.value.ID
- || !EnumFlag(TraitCombatConfigFlags(*traitConfig.value.CombatConfigFlags)).HasFlag(TraitCombatConfigFlags::ActiveForSpec))
- continue;
- }
-
- for (UF::TraitEntry const& traitEntry : traitConfig.value.Entries)
- if (traitEntry.TraitNodeEntryID == traitNodeEntryId)
- return traitEntry.Rank;
- }
- return {};
- };
+ if (TraitConfigType(*traitConfig.value.Type) == TraitConfigType::Combat)
+ {
+ if (int32(*player->m_activePlayerData->ActiveCombatTraitConfigID) != *traitConfig.value.ID
+ || !EnumFlag(TraitCombatConfigFlags(*traitConfig.value.CombatConfigFlags)).HasFlag(TraitCombatConfigFlags::ActiveForSpec))
+ continue;
+ }
- std::array<bool, std::tuple_size_v<decltype(condition->TraitNodeEntryID)>> results;
- results.fill(true);
- for (std::size_t i = 0; i < condition->TraitNodeEntryID.size(); ++i)
- {
- if (!condition->TraitNodeEntryID[i])
- continue;
+ for (UF::TraitEntry const& traitEntry : traitConfig.value.Entries)
+ if (traitEntry.TraitNodeEntryID == traitNodeEntryId)
+ return traitEntry.Rank;
+ }
+ return {};
+ }();
- Optional<int32> rank = getTraitNodeEntryRank(condition->TraitNodeEntryID[i]);
- if (!rank)
- results[i] = false;
- else if (condition->TraitNodeEntryMinRank[i] && rank < condition->TraitNodeEntryMinRank[i])
- results[i] = false;
- else if (condition->TraitNodeEntryMaxRank[i] && rank > condition->TraitNodeEntryMaxRank[i])
- results[i] = false;
- }
+ return rank
+ && (!minRank || *rank >= minRank)
+ && (!maxRank || *rank <= maxRank);
+ }, player, condition->TraitNodeEntryID, condition->TraitNodeEntryMinRank, condition->TraitNodeEntryMaxRank);
if (!PlayerConditionLogic(condition->TraitNodeEntryLogic, results))
return false;
diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h
index 53dc4e45db5..15216bd4486 100644
--- a/src/server/game/DataStores/DB2Structure.h
+++ b/src/server/game/DataStores/DB2Structure.h
@@ -3291,6 +3291,8 @@ struct PlayerConditionEntry
std::array<int32, 4> TraitNodeEntryID;
std::array<uint16, 4> TraitNodeEntryMinRank;
std::array<uint16, 4> TraitNodeEntryMaxRank;
+
+ EnumFlag<PlayerConditionFlags> GetFlags() const { return static_cast<PlayerConditionFlags>(Flags); }
};
struct PlayerDataElementAccountEntry
diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h
index 7d185003a39..35e9b52be9f 100644
--- a/src/server/game/DataStores/DBCEnums.h
+++ b/src/server/game/DataStores/DBCEnums.h
@@ -2074,6 +2074,25 @@ enum PhaseUseFlagsValues : uint8
PHASE_USE_FLAGS_ALL = PHASE_USE_FLAGS_ALWAYS_VISIBLE | PHASE_USE_FLAGS_INVERSE
};
+enum class PlayerConditionFlags : int32
+{
+ ClientExecutable = 0x0001,
+ CheckAchievementsOnAllChars = 0x0002,
+ ComparePowerToMax = 0x0004,
+ Invert = 0x0008,
+ IsAtMaxExpansionLevel = 0x0010,
+ WithinOrAboveRecord = 0x0020,
+ UseEffectiveLevel = 0x0040,
+ InvertContentTuning = 0x0080,
+ Disabled = 0x0100,
+ InvertModifierTree = 0x0200,
+ NotRecentlyTransferred = 0x0400,
+ IncludeLevelDelta = 0x0800,
+ CheckAccountCombinedQuests = 0x1000 // NYI - checks PLAYER_DATA_FLAG_ACCOUNT_COMBINED_QUESTS_INDEX
+};
+
+DEFINE_ENUM_FLAG(PlayerConditionFlags);
+
enum class PlayerConditionLfgStatus : uint8
{
InLFGDungeon = 1,