diff options
author | Shauren <shauren.trinity@gmail.com> | 2021-06-07 15:37:34 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2021-06-07 15:37:34 +0200 |
commit | d0be92ec0ad0334c38b4073a7e24a571982b17da (patch) | |
tree | 7b3fecbd3345b28a7cfb7e40dfeacc2f50adc33a /src | |
parent | 626c8f5de12daac6b88989807eba65d3d7a061dd (diff) |
Core/Achievements: Defined all modifier tree types and implemented many of them
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Achievements/AchievementMgr.cpp | 10 | ||||
-rw-r--r-- | src/server/game/Achievements/AchievementMgr.h | 1 | ||||
-rw-r--r-- | src/server/game/Achievements/CriteriaHandler.cpp | 1329 | ||||
-rw-r--r-- | src/server/game/BattlePets/BattlePetMgr.cpp | 10 | ||||
-rw-r--r-- | src/server/game/BattlePets/BattlePetMgr.h | 5 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2Stores.cpp | 11 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2Stores.h | 1 | ||||
-rw-r--r-- | src/server/game/DataStores/DBCEnums.h | 644 | ||||
-rw-r--r-- | src/server/game/Entities/Item/Item.cpp | 23 | ||||
-rw-r--r-- | src/server/game/Entities/Item/Item.h | 1 | ||||
-rw-r--r-- | src/server/game/Entities/Player/CollectionMgr.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 63 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 2 | ||||
-rw-r--r-- | src/server/game/Handlers/CharacterHandler.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Scenarios/Scenario.cpp | 50 | ||||
-rw-r--r-- | src/server/game/Scenarios/Scenario.h | 1 | ||||
-rw-r--r-- | src/server/game/Server/WorldSession.cpp | 5 | ||||
-rw-r--r-- | src/server/game/Server/WorldSession.h | 2 |
18 files changed, 1562 insertions, 600 deletions
diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index 4c632b59113..fd77d880dfc 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -71,6 +71,16 @@ uint32 AchievementMgr::GetAchievementPoints() const return _achievementPoints; } +std::vector<uint32> AchievementMgr::GetCompletedAchievementIds() const +{ + std::vector<uint32> achievementIds; + std::transform(_completedAchievements.begin(), _completedAchievements.end(), std::back_inserter(achievementIds), [](std::pair<uint32 const, CompletedAchievementData> const& achievement) + { + return achievement.first; + }); + return achievementIds; +} + bool AchievementMgr::CanUpdateCriteriaTree(Criteria const* criteria, CriteriaTree const* tree, Player* referencePlayer) const { AchievementEntry const* achievement = tree->Achievement; diff --git a/src/server/game/Achievements/AchievementMgr.h b/src/server/game/Achievements/AchievementMgr.h index c423b756114..f11856a6345 100644 --- a/src/server/game/Achievements/AchievementMgr.h +++ b/src/server/game/Achievements/AchievementMgr.h @@ -56,6 +56,7 @@ public: virtual void CompletedAchievement(AchievementEntry const* entry, Player* referencePlayer) = 0; bool HasAchieved(uint32 achievementId) const; uint32 GetAchievementPoints() const; + std::vector<uint32> GetCompletedAchievementIds() const; protected: bool CanUpdateCriteriaTree(Criteria const* criteria, CriteriaTree const* tree, Player* referencePlayer) const override; diff --git a/src/server/game/Achievements/CriteriaHandler.cpp b/src/server/game/Achievements/CriteriaHandler.cpp index 1366eba31ba..4552cd989c2 100644 --- a/src/server/game/Achievements/CriteriaHandler.cpp +++ b/src/server/game/Achievements/CriteriaHandler.cpp @@ -34,6 +34,7 @@ #include "Group.h" #include "InstanceScript.h" #include "Item.h" +#include "LanguageMgr.h" #include "Log.h" #include "MapManager.h" #include "ObjectMgr.h" @@ -43,6 +44,7 @@ #include "ReputationMgr.h" #include "Scenario.h" #include "ScriptMgr.h" +#include "SpellAuras.h" #include "SpellInfo.h" #include "SpellMgr.h" #include "World.h" @@ -1650,23 +1652,23 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 uint32 secondaryAsset = modifier->SecondaryAsset; uint32 tertiaryAsset = modifier->TertiaryAsset; - switch (CriteriaAdditionalCondition(modifier->Type)) + switch (ModifierTreeType(modifier->Type)) { - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_DRUNK_VALUE: // 1 + case ModifierTreeType::PlayerInebriationLevelEqualOrGreaterThan: // 1 { uint32 inebriation = std::min(std::max<uint32>(referencePlayer->GetDrunkValue(), *referencePlayer->m_playerData->FakeInebriation), 100u); if (inebriation < reqValue) return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_PLAYER_CONDITION: // 2 + case ModifierTreeType::PlayerMeetsCondition: // 2 { PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(reqValue); if (!playerCondition || !ConditionMgr::IsPlayerMeetingCondition(referencePlayer, playerCondition)) return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_ITEM_LEVEL: // 3 + case ModifierTreeType::MinimumItemLevel: // 3 { // miscValue1 is itemid ItemTemplate const* const item = sObjectMgr->GetItemTemplate(uint32(miscValue1)); @@ -1674,47 +1676,47 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_TARGET_CREATURE_ENTRY: // 4 + case ModifierTreeType::TargetCreatureId: // 4 if (!unit || unit->GetEntry() != reqValue) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_PLAYER: // 5 + case ModifierTreeType::TargetIsPlayer: // 5 if (!unit || unit->GetTypeId() != TYPEID_PLAYER) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_DEAD: // 6 + case ModifierTreeType::TargetIsDead: // 6 if (!unit || unit->IsAlive()) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_ENEMY: // 7 + case ModifierTreeType::TargetIsOppositeFaction: // 7 if (!unit || !referencePlayer->IsHostileTo(unit)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_HAS_AURA: // 8 + case ModifierTreeType::PlayerHasAura: // 8 if (!referencePlayer->HasAura(reqValue)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_HAS_AURA_TYPE: // 9 + case ModifierTreeType::PlayerHasAuraEffect: // 9 if (!referencePlayer->HasAuraType(AuraType(reqValue))) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_TARGET_HAS_AURA: // 10 + case ModifierTreeType::TargetHasAura: // 10 if (!unit || !unit->HasAura(reqValue)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_TARGET_HAS_AURA_TYPE: // 11 + case ModifierTreeType::TargetHasAuraEffect: // 11 if (!unit || !unit->HasAuraType(AuraType(reqValue))) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_AURA_STATE: // 12 - if (!referencePlayer->HasAuraState(AuraStateType(reqValue))) + case ModifierTreeType::TargetHasAuraState: // 12 + if (!unit || !unit->HasAuraState(AuraStateType(reqValue))) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_TARGET_AURA_STATE: // 13 - if (!unit || !unit->HasAuraState(AuraStateType(reqValue))) + case ModifierTreeType::PlayerHasAuraState: // 13 + if (!referencePlayer->HasAuraState(AuraStateType(reqValue))) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_ITEM_QUALITY_MIN: // 14 + case ModifierTreeType::ItemQualityIsAtLeast: // 14 { // miscValue1 is itemid ItemTemplate const* const item = sObjectMgr->GetItemTemplate(uint32(miscValue1)); @@ -1722,7 +1724,7 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_ITEM_QUALITY_EQUALS: // 15 + case ModifierTreeType::ItemQualityIsExactly: // 15 { // miscValue1 is itemid ItemTemplate const* const item = sObjectMgr->GetItemTemplate(uint32(miscValue1)); @@ -1730,11 +1732,11 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_IS_ALIVE: // 16 + case ModifierTreeType::PlayerIsAlive: // 16 if (referencePlayer->isDead()) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_AREA_OR_ZONE: // 17 + case ModifierTreeType::PlayerIsInArea: // 17 { uint32 zoneId, areaId; referencePlayer->GetZoneAndAreaId(zoneId, areaId); @@ -1742,7 +1744,7 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_TARGET_AREA_OR_ZONE: // 18 + case ModifierTreeType::TargetIsInArea: // 18 { if (!unit) return false; @@ -1752,49 +1754,57 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_MAP_DIFFICULTY_OLD: // 20 + case ModifierTreeType::ItemId: // 19 + if (miscValue1 != reqValue) + return false; + break; + case ModifierTreeType::LegacyDungeonDifficulty: // 20 { DifficultyEntry const* difficulty = sDifficultyStore.LookupEntry(referencePlayer->GetMap()->GetDifficultyID()); if (!difficulty || difficulty->OldEnumValue == -1 || uint32(difficulty->OldEnumValue) != reqValue) return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_LEVEL_ABOVE_TARGET: // 22 + case ModifierTreeType::PlayerToTargetLevelDeltaGreaterThan: // 21 + if (!unit || referencePlayer->getLevel() < unit->getLevel() + reqValue) + return false; + break; + case ModifierTreeType::TargetToPlayerLevelDeltaGreaterThan: // 22 if (!unit || referencePlayer->getLevel() + reqValue < unit->getLevel()) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_LEVEL_EQUAL_TARGET: // 23 + case ModifierTreeType::PlayerLevelEqualTargetLevel: // 23 if (!unit || referencePlayer->getLevel() != unit->getLevel()) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_ARENA_TYPE: // 24 + case ModifierTreeType::PlayerInArenaWithTeamSize: // 24 { Battleground* bg = referencePlayer->GetBattleground(); if (!bg || !bg->isArena() || bg->GetArenaType() != reqValue) return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_RACE: // 25 + case ModifierTreeType::PlayerRace: // 25 if (referencePlayer->getRace() != reqValue) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_CLASS: // 26 + case ModifierTreeType::PlayerClass: // 26 if (referencePlayer->getClass() != reqValue) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_TARGET_RACE: // 27 + case ModifierTreeType::TargetRace: // 27 if (!unit || unit->GetTypeId() != TYPEID_PLAYER || unit->getRace() != reqValue) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_TARGET_CLASS: // 28 + case ModifierTreeType::TargetClass: // 28 if (!unit || unit->GetTypeId() != TYPEID_PLAYER || unit->getClass() != reqValue) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_MAX_GROUP_MEMBERS: // 29 + case ModifierTreeType::LessThanTappers: // 29 if (referencePlayer->GetGroup() && referencePlayer->GetGroup()->GetMembersCount() >= reqValue) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_TARGET_CREATURE_TYPE: // 30 + case ModifierTreeType::CreatureType: // 30 { if (!unit) return false; @@ -1802,7 +1812,7 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_TARGET_CREATURE_FAMILY: // 31 + case ModifierTreeType::CreatureFamily: // 31 { if (!unit) return false; @@ -1810,41 +1820,44 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_MAP: // 32 + case ModifierTreeType::PlayerMap: // 32 if (referencePlayer->GetMapId() != reqValue) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_CLIENT_VERSION: // 33 + case ModifierTreeType::ClientVersionEqualOrLessThan: // 33 if (reqValue < sRealmList->GetMinorMajorBugfixVersionForBuild(realm.Build)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_BATTLE_PET_TEAM_LEVEL: // 34 + case ModifierTreeType::BattlePetTeamLevel: // 34 for (WorldPackets::BattlePet::BattlePetSlot const& slot : referencePlayer->GetSession()->GetBattlePetMgr()->GetSlots()) - if (slot.Pet.Level != reqValue) + if (slot.Pet.Level < reqValue) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_NOT_IN_GROUP: // 35 + case ModifierTreeType::PlayerIsNotInParty: // 35 if (referencePlayer->GetGroup()) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_IN_GROUP: // 36 + case ModifierTreeType::PlayerIsInParty: // 36 if (!referencePlayer->GetGroup()) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_TITLE_BIT_INDEX: // 38 - // miscValue1 is title's bit index - if (miscValue1 != reqValue) + case ModifierTreeType::HasPersonalRatingEqualOrGreaterThan: // 37 + if (referencePlayer->GetMaxPersonalArenaRatingRequirement(0) < reqValue) + return false; + break; + case ModifierTreeType::HasTitle: // 38 + if (!referencePlayer->HasTitle(reqValue)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_LEVEL: // 39 + case ModifierTreeType::PlayerLevelEqual: // 39 if (referencePlayer->getLevel() != reqValue) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_TARGET_LEVEL: // 40 + case ModifierTreeType::TargetLevelEqual: // 40 if (!unit || unit->GetLevelForTarget(referencePlayer) != reqValue) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_ZONE: // 41 + case ModifierTreeType::PlayerIsInZone: // 41 { uint32 zoneId = referencePlayer->GetAreaId(); if (AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(zoneId)) @@ -1854,7 +1867,7 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_TARGET_ZONE: // 42 + case ModifierTreeType::TargetIsInZone: // 42 { if (!unit) return false; @@ -1866,55 +1879,55 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_HEALTH_PCT_LOWER: // 43 + case ModifierTreeType::PlayerHealthBelowPercent: // 43 if (referencePlayer->GetHealthPct() > float(reqValue)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_HEALTH_PCT_GREATER: // 44 + case ModifierTreeType::PlayerHealthAbovePercent: // 44 if (referencePlayer->GetHealthPct() < float(reqValue)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_HEALTH_PCT_EQUAL: // 45 + case ModifierTreeType::PlayerHealthEqualsPercent: // 45 if (referencePlayer->GetHealthPct() != float(reqValue)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_TARGET_HEALTH_PCT_LOWER: // 46 + case ModifierTreeType::TargetHealthBelowPercent: // 46 if (!unit || unit->GetHealthPct() > float(reqValue)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_TARGET_HEALTH_PCT_GREATER: // 47 + case ModifierTreeType::TargetHealthAbovePercent: // 47 if (!unit || unit->GetHealthPct() < float(reqValue)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_TARGET_HEALTH_PCT_EQUAL: // 48 + case ModifierTreeType::TargetHealthEqualsPercent: // 48 if (!unit || unit->GetHealthPct() != float(reqValue)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_HEALTH_LOWER: // 49 + case ModifierTreeType::PlayerHealthBelowValue: // 49 if (referencePlayer->GetHealth() > reqValue) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_HEALTH_GREATER: // 50 + case ModifierTreeType::PlayerHealthAboveValue: // 50 if (referencePlayer->GetHealth() < reqValue) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_HEALTH_EQUAL: // 51 + case ModifierTreeType::PlayerHealthEqualsValue: // 51 if (referencePlayer->GetHealth() != reqValue) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_TARGET_HEALTH_LOWER: // 52 + case ModifierTreeType::TargetHealthBelowValue: // 52 if (!unit || unit->GetHealth() > reqValue) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_TARGET_HEALTH_GREATER: // 53 + case ModifierTreeType::TargetHealthAboveValue: // 53 if (!unit || unit->GetHealth() < reqValue) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_TARGET_HEALTH_EQUAL: // 54 + case ModifierTreeType::TargetHealthEqualsValue: // 54 if (!unit || unit->GetHealth() != reqValue) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_TARGET_PLAYER_CONDITION: // 55 + case ModifierTreeType::TargetIsPlayerAndMeetsCondition: // 55 { if (!unit || !unit->IsPlayer()) return false; @@ -1924,75 +1937,145 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_MIN_ACHIEVEMENT_POINTS: // 56 + case ModifierTreeType::PlayerHasMoreThanAchievementPoints: // 56 if (referencePlayer->GetAchievementPoints() <= reqValue) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_IN_LFG_DUNGEON: // 57 + case ModifierTreeType::PlayerInLfgDungeon: // 57 if (!ConditionMgr::GetPlayerConditionLfgValue(referencePlayer, PlayerConditionLfgStatus::InLFGDungeon)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_IN_LFG_RANDOM_DUNGEON: // 58 + case ModifierTreeType::PlayerInRandomLfgDungeon: // 58 if (!ConditionMgr::GetPlayerConditionLfgValue(referencePlayer, PlayerConditionLfgStatus::InLFGRandomDungeon)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_IN_LFG_FIRST_RANDOM_DUNGEON: // 59 + case ModifierTreeType::PlayerInFirstRandomLfgDungeon: // 59 if (!ConditionMgr::GetPlayerConditionLfgValue(referencePlayer, PlayerConditionLfgStatus::InLFGFirstRandomDungeon)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_GUILD_REPUTATION: // 62 + case ModifierTreeType::PlayerInRankedArenaMatch: // 60 + { + Battleground const* bg = referencePlayer->GetBattleground(); + if (!bg || !bg->isArena() || !bg->isRated()) + return false; + break; + } + case ModifierTreeType::PlayerInGuildParty: // 61 NYI + return false; + case ModifierTreeType::PlayerGuildReputationEqualOrGreaterThan: // 62 if (referencePlayer->GetReputationMgr().GetReputation(1168) < int32(reqValue)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_RATED_BATTLEGROUND_RATING: // 64 + case ModifierTreeType::PlayerInRatedBattleground: // 63 + { + Battleground const* bg = referencePlayer->GetBattleground(); + if (!bg || !bg->isBattleground() || !bg->isRated()) + return false; + break; + } + case ModifierTreeType::PlayerBattlegroundRatingEqualOrGreaterThan: // 64 if (referencePlayer->GetRBGPersonalRating() < reqValue) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_WORLD_STATE_EXPRESSION: // 67 + case ModifierTreeType::ResearchProjectRarity: // 65 NYI + case ModifierTreeType::ResearchProjectBranch: // 66 NYI + return false; + case ModifierTreeType::WorldStateExpression: // 67 if (WorldStateExpressionEntry const* worldStateExpression = sWorldStateExpressionStore.LookupEntry(reqValue)) return ConditionMgr::IsPlayerMeetingExpression(referencePlayer, worldStateExpression); return false; - case CRITERIA_ADDITIONAL_CONDITION_MAP_DIFFICULTY: // 68 - { - DifficultyEntry const* difficulty = sDifficultyStore.LookupEntry(referencePlayer->GetMap()->GetDifficultyID()); - if (!difficulty || difficulty->ID != reqValue) + case ModifierTreeType::DungeonDifficulty: // 68 + if (referencePlayer->GetMap()->GetDifficultyID() != reqValue) return false; break; - } - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_LEVEL_GREATER: // 69 + case ModifierTreeType::PlayerLevelEqualOrGreaterThan: // 69 if (referencePlayer->getLevel() < reqValue) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_TARGET_LEVEL_GREATER: // 70 + case ModifierTreeType::TargetLevelEqualOrGreaterThan: // 70 if (!unit || unit->getLevel() < reqValue) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_LEVEL_LOWER: // 71 + case ModifierTreeType::PlayerLevelEqualOrLessThan: // 71 if (referencePlayer->getLevel() > reqValue) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_TARGET_LEVEL_LOWER: // 72 + case ModifierTreeType::TargetLevelEqualOrLessThan: // 72 if (!unit || unit->getLevel() > reqValue) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_MODIFIER_TREE: // 73 + case ModifierTreeType::ModifierTree: // 73 if (ModifierTreeNode const* nextModifierTree = sCriteriaMgr->GetModifierTree(reqValue)) return ModifierTreeSatisfied(nextModifierTree, miscValue1, miscValue2, unit, referencePlayer); return false; - case CRITERIA_ADDITIONAL_CONDITION_SCENARIO_ID: // 74 + case ModifierTreeType::PlayerScenario: // 74 { Scenario const* scenario = referencePlayer->GetScenario(); - if (!scenario) - return false; - if (scenario->GetEntry()->ID != reqValue) + if (!scenario || scenario->GetEntry()->ID != reqValue) return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_THE_TILLERS_REPUTATION: // 75 + case ModifierTreeType::TillersReputationGreaterThan: // 75 if (referencePlayer->GetReputationMgr().GetReputation(1272) < int32(reqValue)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_SCENARIO_STEP_INDEX: // 82 + case ModifierTreeType::BattlePetAchievementPointsEqualOrGreaterThan: // 76 + { + auto getRootAchievementCategory = [](AchievementEntry const* achievement) + { + int16 category = achievement->Category; + do + { + Achievement_CategoryEntry const* categoryEntry = sAchievementCategoryStore.LookupEntry(category); + if (!categoryEntry || categoryEntry->Parent == -1) + break; + + category = categoryEntry->Parent; + } while (true); + + return category; + }; + + uint32 petAchievementPoints = 0; + for (uint32 achievementId : referencePlayer->GetCompletedAchievementIds()) + { + AchievementEntry const* achievement = sAchievementStore.AssertEntry(achievementId); + if (getRootAchievementCategory(achievement) == ACHIVEMENT_CATEGORY_PET_BATTLES) + petAchievementPoints += uint32(achievement->Points); + } + + if (petAchievementPoints < reqValue) + return false; + break; + } + case ModifierTreeType::UniqueBattlePetsEqualOrGreaterThan: // 77 + if (referencePlayer->GetSession()->GetBattlePetMgr()->GetPetUniqueSpeciesCount() < reqValue) + return false; + break; + case ModifierTreeType::BattlePetType: // 78 + { + BattlePetSpeciesEntry const* speciesEntry = sBattlePetSpeciesStore.LookupEntry(miscValue1); + if (!speciesEntry || speciesEntry->PetTypeEnum != reqValue) + return false; + break; + } + case ModifierTreeType::BattlePetHealthPercentLessThan: // 79 NYI - use target battle pet here, the one we were just battling + return false; + case ModifierTreeType::GuildGroupMemberCountEqualOrGreaterThan: // 80 + { + uint32 guildMemberCount = 0; + if (Group const* group = referencePlayer->GetGroup()) + for (GroupReference const* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) + if (itr->GetSource()->GetGuildId() == referencePlayer->GetGuildId()) + ++guildMemberCount; + + if (guildMemberCount < reqValue) + return false; + break; + } + case ModifierTreeType::BattlePetOpponentCreatureId: // 81 NYI + return false; + case ModifierTreeType::PlayerScenarioStep: // 82 { Scenario const* scenario = referencePlayer->GetScenario(); if (!scenario) @@ -2001,81 +2084,141 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_IS_ON_QUEST: // 84 + case ModifierTreeType::ChallengeModeMedal: // 83 + return false; // OBSOLETE + case ModifierTreeType::PlayerOnQuest: // 84 if (referencePlayer->FindQuestSlot(reqValue) == MAX_QUEST_LOG_SIZE) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_EXALTED_WITH_FACTION: // 85 + case ModifierTreeType::ExaltedWithFaction: // 85 if (referencePlayer->GetReputationMgr().GetReputation(reqValue) < 42000) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_HAS_ACHIEVEMENT: // 86 - case CRITERIA_ADDITIONAL_CONDITION_HAS_ACHIEVEMENT_ON_CHARACTER: // 87 + case ModifierTreeType::EarnedAchievementOnAccount: // 86 + case ModifierTreeType::EarnedAchievementOnPlayer: // 87 if (!referencePlayer->HasAchieved(reqValue)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_CLOUD_SERPENT_REPUTATION: // 88 + case ModifierTreeType::OrderOfTheCloudSerpentReputationGreaterThan: // 88 if (referencePlayer->GetReputationMgr().GetReputation(1271) < int32(reqValue)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_BATTLE_PET_SPECIES: // 91 + case ModifierTreeType::BattlePetQuality: // 89 NYI + case ModifierTreeType::BattlePetFightWasPVP: // 90 NYI + return false; + case ModifierTreeType::BattlePetSpecies: // 91 if (miscValue1 != reqValue) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_ACTIVE_EXPANSION: // 92 - if (referencePlayer->GetSession()->GetExpansion() < reqValue) + case ModifierTreeType::ServerExpansionEqualOrGreaterThan: // 92 + if (sWorld->getIntConfig(CONFIG_EXPANSION) < reqValue) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_FACTION_STANDING: // 95 + case ModifierTreeType::PlayerHasBattlePetJournalLock: // 93 + if (!referencePlayer->GetSession()->GetBattlePetMgr()->HasJournalLock()) + return false; + break; + case ModifierTreeType::FriendshipRepReactionIsMet: // 94 + { + FriendshipRepReactionEntry const* friendshipRepReaction = sFriendshipRepReactionStore.LookupEntry(reqValue); + if (!friendshipRepReaction) + return false; + FriendshipReputationEntry const* friendshipReputation = sFriendshipReputationStore.LookupEntry(friendshipRepReaction->FriendshipRepID); + if (!friendshipReputation) + return false; + if (referencePlayer->GetReputation(friendshipReputation->FactionID) < int32(friendshipRepReaction->ReactionThreshold)) + return false; + break; + } + case ModifierTreeType::ReputationWithFactionIsEqualOrGreaterThan: // 95 if (referencePlayer->GetReputationMgr().GetReputation(reqValue) < int32(secondaryAsset)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_SEX: // 97 + case ModifierTreeType::ItemClassAndSubclass: // 96 + { + ItemTemplate const* item = sObjectMgr->GetItemTemplate(miscValue1); + if (!item || item->GetClass() != reqValue || item->GetSubClass() != secondaryAsset) + return false; + break; + } + case ModifierTreeType::PlayerGender: // 97 if (referencePlayer->getGender() != uint8(reqValue)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_NATIVE_SEX: // 98 + case ModifierTreeType::PlayerNativeGender: // 98 if (referencePlayer->GetNativeSex() != uint8(reqValue)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_SKILL: // 99 + case ModifierTreeType::PlayerSkillEqualOrGreaterThan: // 99 if (referencePlayer->GetPureSkillValue(reqValue) < uint16(secondaryAsset)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_NORMAL_PHASE_SHIFT: // 101 + case ModifierTreeType::PlayerLanguageSkillEqualOrGreaterThan: // 100 + { + auto languageDescs = sLanguageMgr->GetLanguageDescById(Language(reqValue)); + bool hasLanguageSkil = std::any_of(languageDescs.begin(), languageDescs.end(), [&](std::pair<uint32 const, LanguageDesc> const& desc) + { + return referencePlayer->GetSkillValue(desc.second.SkillId) >= secondaryAsset; + }); + if (!hasLanguageSkil) + return false; + break; + } + case ModifierTreeType::PlayerIsInNormalPhase: // 101 if (!PhasingHandler::InDbPhaseShift(referencePlayer, 0, 0, 0)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_IN_PHASE: // 102 + case ModifierTreeType::PlayerIsInPhase: // 102 if (!PhasingHandler::InDbPhaseShift(referencePlayer, 0, reqValue, 0)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_NOT_IN_PHASE: // 103 - if (PhasingHandler::InDbPhaseShift(referencePlayer, 0, reqValue, 0)) + case ModifierTreeType::PlayerIsInPhaseGroup: // 103 + if (!PhasingHandler::InDbPhaseShift(referencePlayer, 0, 0, reqValue)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_HAS_SPELL: // 104 + case ModifierTreeType::PlayerKnowsSpell: // 104 if (!referencePlayer->HasSpell(reqValue)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_ITEM_COUNT: // 105 + case ModifierTreeType::PlayerHasItemQuantity: // 105 if (referencePlayer->GetItemCount(reqValue, false) < secondaryAsset) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_ACCOUNT_EXPANSION: // 106 - if (referencePlayer->GetSession()->GetAccountExpansion() < reqValue) + case ModifierTreeType::PlayerExpansionLevelEqualOrGreaterThan: // 106 + if (referencePlayer->GetSession()->GetExpansion() < reqValue) + return false; + break; + case ModifierTreeType::PlayerHasAuraWithLabel: // 107 + if (!referencePlayer->HasAura([labelId = reqValue](Aura const* aura) { return aura->GetSpellInfo()->HasLabel(labelId); })) + return false; + break; + case ModifierTreeType::PlayersRealmWorldState: // 108 + if (sWorld->getWorldState(reqValue) != secondaryAsset) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_REWARDED_QUEST: // 110 + case ModifierTreeType::TimeBetween: // 109 + { + ByteBuffer unpacker; + unpacker << reqValue; + time_t from = unpacker.ReadPackedTime(); + unpacker.rpos(0); + unpacker.wpos(0); + unpacker << secondaryAsset; + time_t to = unpacker.ReadPackedTime(); + if (GameTime::GetGameTime() < from || GameTime::GetGameTime() > to) + return false; + break; + } + case ModifierTreeType::PlayerHasCompletedQuest: // 110 if (uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(reqValue)) if (!(referencePlayer->m_activePlayerData->QuestCompleted[((questBit - 1) >> 6)] & (UI64LIT(1) << ((questBit - 1) & 63)))) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_COMPLETED_QUEST: // 111 + case ModifierTreeType::PlayerIsReadyToTurnInQuest: // 111 if (referencePlayer->GetQuestStatus(reqValue) != QUEST_STATUS_COMPLETE) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_COMPLETED_QUEST_OBJECTIVE: // 112 + case ModifierTreeType::PlayerHasCompletedQuestObjective: // 112 { QuestObjective const* objective = sObjectMgr->GetQuestObjective(reqValue); if (!objective) @@ -2088,7 +2231,7 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_EXPLORED_AREA: // 113 + case ModifierTreeType::PlayerHasExploredArea: // 113 { AreaTableEntry const* areaTable = sAreaTableStore.LookupEntry(reqValue); if (!areaTable) @@ -2102,11 +2245,15 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_ITEM_COUNT_INCLUDING_BANK: // 114 + case ModifierTreeType::PlayerHasItemQuantityIncludingBank: // 114 if (referencePlayer->GetItemCount(reqValue, true) < secondaryAsset) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_PVP_FACTION_INDEX: // 116 + case ModifierTreeType::Weather: // 115 + if (referencePlayer->GetMap()->GetZoneWeather(referencePlayer->GetZoneId()) != WeatherState(reqValue)) + return false; + break; + case ModifierTreeType::PlayerFaction: // 116 { ChrRacesEntry const* race = sChrRacesStore.LookupEntry(referencePlayer->getRace()); if (!race) @@ -2125,93 +2272,113 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_LFG_VALUE_EQUAL: // 117 + case ModifierTreeType::LfgStatusEqual: // 117 if (ConditionMgr::GetPlayerConditionLfgValue(referencePlayer, PlayerConditionLfgStatus(reqValue)) != secondaryAsset) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_LFG_VALUE_GREATER: // 118 + case ModifierTreeType::LFgStatusEqualOrGreaterThan: // 118 if (ConditionMgr::GetPlayerConditionLfgValue(referencePlayer, PlayerConditionLfgStatus(reqValue)) < secondaryAsset) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_CURRENCY_AMOUNT: // 119 + case ModifierTreeType::PlayerHasCurrencyEqualOrGreaterThan: // 119 if (!referencePlayer->HasCurrency(reqValue, secondaryAsset)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_CURRENCY_TRACKED_AMOUNT: // 121 + case ModifierTreeType::TargetThreatListSizeLessThan: // 120 + { + if (!unit || !unit->CanHaveThreatList()) + return false; + if (unit->GetThreatManager().GetThreatListSize() >= reqValue) + return false; + break; + } + case ModifierTreeType::PlayerHasTrackedCurrencyEqualOrGreaterThan: // 121 if (referencePlayer->GetTrackedCurrencyCount(reqValue) < secondaryAsset) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_MAP_INSTANCE_TYPE: // 122 + case ModifierTreeType::PlayerMapInstanceType: // 122 if (referencePlayer->GetMap()->GetEntry()->InstanceType != int8(reqValue)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_MENTOR: // 123 + case ModifierTreeType::PlayerInTimeWalkerInstance: // 123 if (!referencePlayer->HasPlayerFlag(PLAYER_FLAGS_TIMEWALKING)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_GARRISON_LEVEL_ABOVE: // 126 + case ModifierTreeType::PvpSeasonIsActive: // 124 + if (!sWorld->getBoolConfig(CONFIG_ARENA_SEASON_IN_PROGRESS)) + return false; + break; + case ModifierTreeType::PvpSeason: // 125 + if (sWorld->getIntConfig(CONFIG_ARENA_SEASON_ID) != reqValue) + return false; + break; + case ModifierTreeType::GarrisonTierEqualOrGreaterThan: // 126 { Garrison const* garrison = referencePlayer->GetGarrison(); if (!garrison || garrison->GetType() != GarrisonType(secondaryAsset) || garrison->GetSiteLevel()->GarrLevel < reqValue) return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWERS_ABOVE_LEVEL: // 127 + case ModifierTreeType::GarrisonFollowersWithLevelEqualOrGreaterThan: // 127 { Garrison const* garrison = referencePlayer->GetGarrison(); - if (!garrison || garrison->GetType() != GarrisonType(tertiaryAsset)) + if (!garrison) return false; - uint32 followerCount = garrison->CountFollowers([secondaryAsset](Garrison::Follower const& follower) + uint32 followerCount = garrison->CountFollowers([secondaryAsset, tertiaryAsset](Garrison::Follower const& follower) { - return follower.PacketInfo.FollowerLevel >= secondaryAsset; + GarrFollowerEntry const* garrFollower = sGarrFollowerStore.AssertEntry(follower.PacketInfo.GarrFollowerID); + return garrFollower->GarrFollowerTypeID == tertiaryAsset && follower.PacketInfo.FollowerLevel >= secondaryAsset; }); if (followerCount < reqValue) return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWERS_ABOVE_QUALITY: // 128 + case ModifierTreeType::GarrisonFollowersWithQualityEqualOrGreaterThan: // 128 { Garrison const* garrison = referencePlayer->GetGarrison(); - if (!garrison || garrison->GetType() != GarrisonType(tertiaryAsset)) + if (!garrison) return false; - uint32 followerCount = garrison->CountFollowers([secondaryAsset](Garrison::Follower const& follower) + uint32 followerCount = garrison->CountFollowers([secondaryAsset, tertiaryAsset](Garrison::Follower const& follower) { - return follower.PacketInfo.Quality >= secondaryAsset; + GarrFollowerEntry const* garrFollower = sGarrFollowerStore.AssertEntry(follower.PacketInfo.GarrFollowerID); + return garrFollower->GarrFollowerTypeID == tertiaryAsset && follower.PacketInfo.Quality >= secondaryAsset; }); if (followerCount < reqValue) return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_ABOVE_LEVEL_WITH_ABILITY: // 129 + case ModifierTreeType::GarrisonFollowerWithAbilityAtLevelEqualOrGreaterThan: // 129 { Garrison const* garrison = referencePlayer->GetGarrison(); - if (!garrison || garrison->GetType() != GarrisonType(tertiaryAsset)) + if (!garrison) return false; - uint32 followerCount = garrison->CountFollowers([reqValue, secondaryAsset](Garrison::Follower const& follower) + uint32 followerCount = garrison->CountFollowers([reqValue, secondaryAsset, tertiaryAsset](Garrison::Follower const& follower) { - return follower.PacketInfo.FollowerLevel >= reqValue && follower.HasAbility(secondaryAsset); + GarrFollowerEntry const* garrFollower = sGarrFollowerStore.AssertEntry(follower.PacketInfo.GarrFollowerID); + return garrFollower->GarrFollowerTypeID == tertiaryAsset && follower.PacketInfo.FollowerLevel >= reqValue && follower.HasAbility(secondaryAsset); }); if (followerCount < 1) return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_ABOVE_LEVEL_WITH_TRAIT: // 130 + case ModifierTreeType::GarrisonFollowerWithTraitAtLevelEqualOrGreaterThan: // 130 { Garrison const* garrison = referencePlayer->GetGarrison(); - if (!garrison || garrison->GetType() != GarrisonType(tertiaryAsset)) + if (!garrison) return false; GarrAbilityEntry const* traitEntry = sGarrAbilityStore.LookupEntry(secondaryAsset); if (!traitEntry || !(traitEntry->Flags & GARRISON_ABILITY_FLAG_TRAIT)) return false; - uint32 followerCount = garrison->CountFollowers([reqValue, secondaryAsset](Garrison::Follower const& follower) + uint32 followerCount = garrison->CountFollowers([reqValue, secondaryAsset, tertiaryAsset](Garrison::Follower const& follower) { - return follower.PacketInfo.FollowerLevel >= reqValue && follower.HasAbility(secondaryAsset); + GarrFollowerEntry const* garrFollower = sGarrFollowerStore.AssertEntry(follower.PacketInfo.GarrFollowerID); + return garrFollower->GarrFollowerTypeID == tertiaryAsset && follower.PacketInfo.FollowerLevel >= reqValue && follower.HasAbility(secondaryAsset); }); if (followerCount < 1) return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_WITH_ABILITY_IN_BUILDING: // 131 + case ModifierTreeType::GarrisonFollowerWithAbilityAssignedToBuilding: // 131 { Garrison const* garrison = referencePlayer->GetGarrison(); if (!garrison || garrison->GetType() != GarrisonType(tertiaryAsset)) @@ -2227,7 +2394,7 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_WITH_TRAIT_IN_BUILDING: // 132 + case ModifierTreeType::GarrisonFollowerWithTraitAssignedToBuilding: // 132 { Garrison const* garrison = referencePlayer->GetGarrison(); if (!garrison || garrison->GetType() != GarrisonType(tertiaryAsset)) @@ -2246,7 +2413,7 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_ABOVE_LEVEL_IN_BUILDING: // 133 + case ModifierTreeType::GarrisonFollowerWithLevelAssignedToBuilding: // 133 { Garrison const* garrison = referencePlayer->GetGarrison(); if (!garrison || garrison->GetType() != GarrisonType(tertiaryAsset)) @@ -2264,7 +2431,7 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_GARRISON_BUILDING_ABOVE_LEVEL: // 134 + case ModifierTreeType::GarrisonBuildingWithLevelEqualOrGreaterThan: // 134 { Garrison* garrison = referencePlayer->GetGarrison(); if (!garrison || garrison->GetType() != GarrisonType(tertiaryAsset)) @@ -2282,19 +2449,34 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 } return false; } - case CRITERIA_ADDITIONAL_CONDITION_GARRISON_BLUEPRINT: // 135 + case ModifierTreeType::HasBlueprintForGarrisonBuilding: // 135 { - GarrBuildingEntry const* blueprintBuilding = sGarrBuildingStore.LookupEntry(reqValue); - if (!blueprintBuilding) - return false; Garrison const* garrison = referencePlayer->GetGarrison(); - if (!garrison || garrison->GetType() != GarrisonType(blueprintBuilding->GarrTypeID)) + if (!garrison || garrison->GetType() != GarrisonType(secondaryAsset)) return false; if (!garrison->HasBlueprint(reqValue)) return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_GARRISON_BUILDING_INACTIVE: // 140 + case ModifierTreeType::HasGarrisonBuildingSpecialization: // 136 + return false; // OBSOLETE + case ModifierTreeType::AllGarrisonPlotsAreFull: // 137 + { + Garrison* garrison = referencePlayer->GetGarrison(); + if (!garrison || garrison->GetType() != GarrisonType(reqValue)) + return false; + for (Garrison::Plot const* plot : garrison->GetPlots()) + if (!plot->BuildingInfo.PacketInfo) + return false; + break; + } + case ModifierTreeType::PlayerIsInOwnGarrison: // 138 + if (!referencePlayer->GetMap()->IsGarrison() || referencePlayer->GetMap()->GetInstanceId() != referencePlayer->GetGUID().GetCounter()) + return false; + break; + case ModifierTreeType::GarrisonShipmentOfTypeIsPending: // 139 NYI + return false; + case ModifierTreeType::GarrisonBuildingIsUnderConstruction: // 140 { GarrBuildingEntry const* building = sGarrBuildingStore.LookupEntry(reqValue); if (!building) @@ -2311,7 +2493,9 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 } return false; } - case CRITERIA_ADDITIONAL_CONDITION_GARRISON_BUILDING_EQUAL_LEVEL: // 142 + case ModifierTreeType::GarrisonMissionHasBeenCompleted: // 141 NYI + return false; + case ModifierTreeType::GarrisonBuildingLevelEqual: // 142 { Garrison* garrison = referencePlayer->GetGarrison(); if (!garrison || garrison->GetType() != GarrisonType(tertiaryAsset)) @@ -2322,14 +2506,14 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 continue; GarrBuildingEntry const* building = sGarrBuildingStore.LookupEntry(plot->BuildingInfo.PacketInfo->GarrBuildingID); - if (!building || building->UpgradeLevel != reqValue || building->BuildingType != secondaryAsset) + if (!building || building->UpgradeLevel != secondaryAsset || building->BuildingType != reqValue) continue; return true; } return false; } - case CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_WITH_ABILITY: // 143 + case ModifierTreeType::GarrisonFollowerHasAbility: // 143 { Garrison const* garrison = referencePlayer->GetGarrison(); if (!garrison || garrison->GetType() != GarrisonType(secondaryAsset)) @@ -2353,7 +2537,7 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 } break; } - case CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_WITH_TRAIT: // 144 + case ModifierTreeType::GarrisonFollowerHasTrait: // 144 { GarrAbilityEntry const* traitEntry = sGarrAbilityStore.LookupEntry(reqValue); if (!traitEntry || !(traitEntry->Flags & GARRISON_ABILITY_FLAG_TRAIT)) @@ -2378,7 +2562,7 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 } break; } - case CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_ABOVE_QUALITY_WOD: // 145 + case ModifierTreeType::GarrisonFollowerQualityEqual: // 145 { Garrison const* garrison = referencePlayer->GetGarrison(); if (!garrison || garrison->GetType() != GARRISON_TYPE_GARRISON) @@ -2400,7 +2584,7 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 } break; } - case CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_EQUAL_LEVEL: // 146 + case ModifierTreeType::GarrisonFollowerLevelEqual: // 146 { Garrison const* garrison = referencePlayer->GetGarrison(); if (!garrison || garrison->GetType() != GarrisonType(secondaryAsset)) @@ -2408,21 +2592,56 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 if (miscValue1) { Garrison::Follower const* follower = garrison->GetFollower(miscValue1); - if (!follower || follower->PacketInfo.FollowerLevel < reqValue) + if (!follower || follower->PacketInfo.FollowerLevel != reqValue) return false; } else { uint32 followerCount = garrison->CountFollowers([reqValue](Garrison::Follower const& follower) { - return follower.PacketInfo.FollowerLevel >= reqValue; + return follower.PacketInfo.FollowerLevel == reqValue; }); if (followerCount < 1) return false; } break; } - case CRITERIA_ADDITIONAL_CONDITION_BATTLE_PET_SPECIES_IN_TEAM: // 151 + case ModifierTreeType::GarrisonMissionIsRare: // 147 NYI + case ModifierTreeType::GarrisonMissionIsElite: // 148 NYI + return false; + case ModifierTreeType::CurrentGarrisonBuildingLevelEqual: // 149 + { + if (!miscValue1) + return false; + Garrison* garrison = referencePlayer->GetGarrison(); + if (!garrison) + return false; + for (Garrison::Plot const* plot : garrison->GetPlots()) + { + if (!plot->BuildingInfo.PacketInfo || plot->BuildingInfo.PacketInfo->GarrBuildingID != miscValue1) + continue; + + GarrBuildingEntry const* building = sGarrBuildingStore.LookupEntry(plot->BuildingInfo.PacketInfo->GarrBuildingID); + if (!building || building->UpgradeLevel != reqValue) + continue; + + return true; + } + break; + } + case ModifierTreeType::GarrisonPlotInstanceHasBuildingThatIsReadyToActivate: // 150 + { + Garrison* garrison = referencePlayer->GetGarrison(); + if (!garrison) + return false; + Garrison::Plot const* plot = garrison->GetPlot(reqValue); + if (!plot) + return false; + if (!plot->BuildingInfo.CanActivate() || !plot->BuildingInfo.PacketInfo || plot->BuildingInfo.PacketInfo->Active) + return false; + break; + } + case ModifierTreeType::BattlePetTeamWithSpeciesEqualOrGreaterThan: // 151 { uint32 count = 0; for (WorldPackets::BattlePet::BattlePetSlot const& slot : referencePlayer->GetSession()->GetBattlePetMgr()->GetSlots()) @@ -2432,7 +2651,7 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_BATTLE_PET_FAMILY_IN_TEAM: // 152 + case ModifierTreeType::BattlePetTeamWithTypeEqualOrGreaterThan: // 152 { uint32 count = 0; for (WorldPackets::BattlePet::BattlePetSlot const& slot : referencePlayer->GetSession()->GetBattlePetMgr()->GetSlots()) @@ -2443,113 +2662,219 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_ID: // 157 + case ModifierTreeType::PetBattleLastAbility: // 153 NYI + case ModifierTreeType::PetBattleLastAbilityType: // 154 NYI + return false; + case ModifierTreeType::BattlePetTeamWithAliveEqualOrGreaterThan: // 155 + { + uint32 count = 0; + for (WorldPackets::BattlePet::BattlePetSlot const& slot : referencePlayer->GetSession()->GetBattlePetMgr()->GetSlots()) + if (slot.Pet.Health > 0) + ++count; + if (count < reqValue) + return false; + break; + } + case ModifierTreeType::HasGarrisonBuildingActiveSpecialization: // 156 + return false; // OBSOLETE + case ModifierTreeType::HasGarrisonFollower: // 157 { Garrison const* garrison = referencePlayer->GetGarrison(); if (!garrison) return false; - if (miscValue1) + uint32 followerCount = garrison->CountFollowers([reqValue](Garrison::Follower const& follower) { - Garrison::Follower const* follower = garrison->GetFollower(miscValue1); - if (!follower || follower->PacketInfo.GarrFollowerID != reqValue) - return false; - } - else + return follower.PacketInfo.GarrFollowerID == reqValue; + }); + if (followerCount < 1) + return false; + break; + } + case ModifierTreeType::PlayerQuestObjectiveProgressEqual: // 158 + { + QuestObjective const* objective = sObjectMgr->GetQuestObjective(reqValue); + if (!objective) + return false; + if (referencePlayer->GetQuestObjectiveData(*objective) != int32(secondaryAsset)) + return false; + break; + } + case ModifierTreeType::PlayerQuestObjectiveProgressEqualOrGreaterThan: // 159 + { + QuestObjective const* objective = sObjectMgr->GetQuestObjective(reqValue); + if (!objective) + return false; + if (referencePlayer->GetQuestObjectiveData(*objective) < int32(secondaryAsset)) + return false; + break; + } + case ModifierTreeType::IsPTRRealm: // 160 + case ModifierTreeType::IsBetaRealm: // 161 + case ModifierTreeType::IsQARealm: // 162 + return false; // always false + case ModifierTreeType::GarrisonShipmentContainerIsFull: // 163 + return false; + case ModifierTreeType::PlayerCountIsValidToStartGarrisonInvasion: // 164 + return true; // Only 1 player is required and referencePlayer->GetMap() will ALWAYS have at least the referencePlayer on it + case ModifierTreeType::InstancePlayerCountEqualOrLessThan: // 165 + if (referencePlayer->GetMap()->GetPlayersCountExceptGMs() > reqValue) + return false; + break; + case ModifierTreeType::AllGarrisonPlotsFilledWithBuildingsWithLevelEqualOrGreater: // 166 + { + Garrison* garrison = referencePlayer->GetGarrison(); + if (!garrison || garrison->GetType() != GarrisonType(reqValue)) + return false; + for (Garrison::Plot const* plot : garrison->GetPlots()) { - uint32 followerCount = garrison->CountFollowers([reqValue](Garrison::Follower const& follower) - { - return follower.PacketInfo.GarrFollowerID == reqValue; - }); - if (followerCount < 1) + if (!plot->BuildingInfo.PacketInfo) + return false; + GarrBuildingEntry const* building = sGarrBuildingStore.LookupEntry(plot->BuildingInfo.PacketInfo->GarrBuildingID); + if (!building || building->UpgradeLevel != reqValue) return false; } break; } - case CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_ABOVE_ITEM_LEVEL: // 168 + case ModifierTreeType::GarrisonMissionType: // 167 NYI + return false; + case ModifierTreeType::GarrisonFollowerItemLevelEqualOrGreaterThan: // 168 { + if (!miscValue1) + return false; Garrison const* garrison = referencePlayer->GetGarrison(); if (!garrison) return false; - if (miscValue1) + uint32 followerCount = garrison->CountFollowers([miscValue1, reqValue](Garrison::Follower const& follower) { - Garrison::Follower const* follower = garrison->GetFollower(miscValue1); - if (!follower || follower->PacketInfo.GarrFollowerID != reqValue) - return false; - } - else - { - uint32 followerCount = garrison->CountFollowers([reqValue](Garrison::Follower const& follower) - { - return follower.GetItemLevel() >= reqValue; - }); - if (followerCount < 1) - return false; - } + return follower.PacketInfo.GarrFollowerID == miscValue1 && follower.GetItemLevel() >= reqValue; + }); + if (followerCount < 1) + return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWERS_ABOVE_ITEM_LEVEL: // 169 + case ModifierTreeType::GarrisonFollowerCountWithItemLevelEqualOrGreaterThan: // 169 { Garrison const* garrison = referencePlayer->GetGarrison(); - if (!garrison || garrison->GetType() != GarrisonType(tertiaryAsset)) + if (!garrison) return false; - uint32 followerCount = garrison->CountFollowers([secondaryAsset](Garrison::Follower const& follower) + uint32 followerCount = garrison->CountFollowers([secondaryAsset, tertiaryAsset](Garrison::Follower const& follower) { - return follower.GetItemLevel() >= secondaryAsset; + GarrFollowerEntry const* garrFollower = sGarrFollowerStore.AssertEntry(follower.PacketInfo.GarrFollowerID); + return garrFollower->GarrFollowerTypeID == tertiaryAsset && follower.GetItemLevel() >= secondaryAsset; }); if (followerCount < reqValue) return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_GARRISON_LEVEL_EQUAL: // 170 + case ModifierTreeType::GarrisonTierEqual: // 170 { Garrison const* garrison = referencePlayer->GetGarrison(); - if (!garrison || garrison->GetType() != GARRISON_TYPE_GARRISON || garrison->GetSiteLevel()->GarrLevel != reqValue) + if (!garrison || garrison->GetType() != GarrisonType(secondaryAsset) || garrison->GetSiteLevel()->GarrLevel != reqValue) return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_TARGETING_CORPSE: // 173 + case ModifierTreeType::InstancePlayerCountEqual: // 171 + if (referencePlayer->GetMap()->GetPlayers().getSize() != reqValue) + return false; + break; + case ModifierTreeType::CurrencyId: // 172 + if (miscValue1 != reqValue) + return false; + break; + case ModifierTreeType::SelectionIsPlayerCorpse: // 173 if (referencePlayer->GetTarget().GetHigh() != HighGuid::Corpse) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWERS_LEVEL_EQUAL: // 175 + case ModifierTreeType::PlayerCanAcceptQuest: // 174 + { + Quest const* quest = sObjectMgr->GetQuestTemplate(reqValue); + if (!quest) + return false; + if (!referencePlayer->CanTakeQuest(quest, false)) + return false; + break; + } + case ModifierTreeType::GarrisonFollowerCountWithLevelEqualOrGreaterThan: // 175 { Garrison const* garrison = referencePlayer->GetGarrison(); if (!garrison || garrison->GetType() != GarrisonType(tertiaryAsset)) return false; - uint32 followerCount = garrison->CountFollowers([secondaryAsset](Garrison::Follower const& follower) + uint32 followerCount = garrison->CountFollowers([secondaryAsset, tertiaryAsset](Garrison::Follower const& follower) { - return follower.PacketInfo.FollowerLevel >= secondaryAsset; + GarrFollowerEntry const* garrFollower = sGarrFollowerStore.AssertEntry(follower.PacketInfo.GarrFollowerID); + return garrFollower->GarrFollowerTypeID == tertiaryAsset && follower.PacketInfo.FollowerLevel == secondaryAsset; }); if (followerCount < reqValue) return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_ID_IN_BUILDING: // 176 + case ModifierTreeType::GarrisonFollowerIsInBuilding: // 176 { Garrison const* garrison = referencePlayer->GetGarrison(); - if (!garrison || garrison->GetType() != GARRISON_TYPE_GARRISON) + if (!garrison) return false; uint32 followerCount = garrison->CountFollowers([reqValue, secondaryAsset](Garrison::Follower const& follower) { - if (follower.PacketInfo.GarrFollowerID != reqValue) - return false; - GarrBuildingEntry const* followerBuilding = sGarrBuildingStore.LookupEntry(follower.PacketInfo.CurrentBuildingID); - if (!followerBuilding) - return false; - return followerBuilding->BuildingType == secondaryAsset; + return follower.PacketInfo.GarrFollowerID == reqValue && follower.PacketInfo.CurrentBuildingID == secondaryAsset; }); if (followerCount < 1) return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_WORLD_PVP_AREA: // 179 + case ModifierTreeType::GarrisonMissionCountLessThan: // 177 NYI + return false; + case ModifierTreeType::GarrisonPlotInstanceCountEqualOrGreaterThan: // 178 { - Battlefield const* bf = sBattlefieldMgr->GetBattlefieldToZoneId(referencePlayer->GetZoneId()); - if (!bf || bf->GetBattleId() != reqValue) + Garrison* garrison = referencePlayer->GetGarrison(); + if (!garrison || garrison->GetType() != GarrisonType(reqValue)) + return false; + uint32 plotCount = 0; + for (Garrison::Plot const* plot : garrison->GetPlots()) + { + GarrPlotInstanceEntry const* garrPlotInstance = sGarrPlotInstanceStore.LookupEntry(plot->PacketInfo.GarrPlotInstanceID); + if (!garrPlotInstance || garrPlotInstance->GarrPlotID != secondaryAsset) + continue; + ++plotCount; + } + if (plotCount < reqValue) + return false; + break; + } + case ModifierTreeType::CurrencySource: // 179 NYI + return false; + case ModifierTreeType::PlayerIsInNotOwnGarrison: // 180 + if (!referencePlayer->GetMap()->IsGarrison() || referencePlayer->GetMap()->GetInstanceId() == referencePlayer->GetGUID().GetCounter()) + return false; + break; + case ModifierTreeType::HasActiveGarrisonFollower: // 181 + { + Garrison const* garrison = referencePlayer->GetGarrison(); + if (!garrison) + return false; + uint32 followerCount = garrison->CountFollowers([reqValue](Garrison::Follower const& follower) + { + return follower.PacketInfo.GarrFollowerID == reqValue && !(follower.PacketInfo.FollowerStatus & FOLLOWER_STATUS_INACTIVE); + }); + if (followerCount < 1) return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWERS_ITEM_LEVEL_ABOVE: // 184 + case ModifierTreeType::PlayerDailyRandomValueMod_X_Equals: // 182 NYI + return false; + case ModifierTreeType::PlayerHasMount: // 183 + { + for (auto&& p : referencePlayer->GetSession()->GetCollectionMgr()->GetAccountMounts()) + { + MountEntry const* mount = sDB2Manager.GetMount(p.first); + if (!mount) + continue; + + if (mount->ID == reqValue) + return true; + } + return false; + } + case ModifierTreeType::GarrisonFollowerCountWithInactiveWithItemLevelEqualOrGreaterThan: // 184 { Garrison const* garrison = referencePlayer->GetGarrison(); if (!garrison) @@ -2565,48 +2890,108 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_USED_LEVEL_BOOST_LESS_THAN_HOURS_AGO: // 188 + case ModifierTreeType::GarrisonFollowerIsOnAMission: // 185 + { + Garrison const* garrison = referencePlayer->GetGarrison(); + if (!garrison) + return false; + uint32 followerCount = garrison->CountFollowers([reqValue](Garrison::Follower const& follower) + { + return follower.PacketInfo.GarrFollowerID == reqValue && follower.PacketInfo.CurrentMissionID != 0; + }); + if (followerCount < 1) + return false; + break; + } + case ModifierTreeType::GarrisonMissionCountInSetLessThan: // 186 NYI + return false; + case ModifierTreeType::GarrisonFollowerType: // 187 + { + GarrFollowerEntry const* garrFollower = sGarrFollowerStore.LookupEntry(miscValue1); + if (!garrFollower || garrFollower->GarrFollowerTypeID != reqValue) + return false; + break; + } + case ModifierTreeType::PlayerUsedBoostLessThanHoursAgoRealTime: // 188 NYI + case ModifierTreeType::PlayerUsedBoostLessThanHoursAgoGameTime: // 189 NYI + return false; + case ModifierTreeType::PlayerIsMercenary: // 190 + if (!referencePlayer->HasPlayerFlagEx(PLAYER_FLAGS_EX_MERCENARY_MODE)) + return false; + break; + case ModifierTreeType::PlayerEffectiveRace: // 191 NYI + case ModifierTreeType::TargetEffectiveRace: // 192 NYI return false; - case CRITERIA_ADDITIONAL_CONDITION_HONOR_LEVEL: // 193 - if (referencePlayer->GetHonorLevel() != reqValue) + case ModifierTreeType::HonorLevelEqualOrGreaterThan: // 193 + if (referencePlayer->GetHonorLevel() < reqValue) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_PRESTIGE_LEVEL: // 194 + case ModifierTreeType::PrestigeLevelEqualOrGreaterThan: // 194 + return false; // OBSOLOTE + case ModifierTreeType::GarrisonMissionIsReadyToCollect: // 195 NYI + case ModifierTreeType::PlayerIsInstanceOwner: // 196 NYI return false; - case CRITERIA_ADDITIONAL_CONDITION_ITEM_MODIFIED_APPEARANCE: // 200 + case ModifierTreeType::PlayerHasHeirloom: // 197 + if (!Trinity::Containers::MapGetValuePtr(referencePlayer->GetSession()->GetCollectionMgr()->GetAccountHeirlooms(), reqValue)) + return false; + break; + case ModifierTreeType::TeamPoints: // 198 NYI + return false; + case ModifierTreeType::PlayerHasToy: // 199 + if (!referencePlayer->GetSession()->GetCollectionMgr()->HasToy(reqValue)) + return false; + break; + case ModifierTreeType::PlayerHasTransmog: // 200 { std::pair<bool, bool> hasAppearance = referencePlayer->GetSession()->GetCollectionMgr()->HasItemAppearance(reqValue); if (!hasAppearance.first || hasAppearance.second) return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_HAS_CHARACTER_RESTRICTIONS: // 203 + case ModifierTreeType::GarrisonTalentSelected: // 201 NYI + case ModifierTreeType::GarrisonTalentResearched: // 202 NYI + return false; + case ModifierTreeType::PlayerHasRestriction: // 203 { - if (referencePlayer->m_activePlayerData->CharacterRestrictions.empty()) + int32 restrictionIndex = referencePlayer->m_activePlayerData->CharacterRestrictions.FindIndexIf([reqValue](UF::CharacterRestriction const& restriction) + { + return restriction.Type == reqValue; + }); + if (restrictionIndex < 0) return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_QUEST_INFO_ID: // 206 + case ModifierTreeType::PlayerCreatedCharacterLessThanHoursAgoRealTime: // 204 NYI + return false; + case ModifierTreeType::PlayerCreatedCharacterLessThanHoursAgoGameTime: // 205 + if (Hours(reqValue) >= Seconds(referencePlayer->GetTotalPlayedTime())) + return false; + break; + case ModifierTreeType::QuestHasQuestInfoId: // 206 { Quest const* quest = sObjectMgr->GetQuestTemplate(miscValue1); if (!quest || quest->GetQuestInfoID() != reqValue) return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_ARTIFACT_APPEARANCE_SET_USED: // 208 + case ModifierTreeType::GarrisonTalentResearchInProgress: // 207 NYI + return false; + case ModifierTreeType::PlayerEquippedArtifactAppearanceSet: // 208 { - for (uint8 slot = EQUIPMENT_SLOT_MAINHAND; slot <= EQUIPMENT_SLOT_RANGED; ++slot) - if (Item* artifact = referencePlayer->GetItemByPos(INVENTORY_SLOT_BAG_0, slot)) + if (Aura const* artifactAura = referencePlayer->GetAura(ARTIFACTS_ALL_WEAPONS_GENERAL_WEAPON_EQUIPPED_PASSIVE)) + if (Item* artifact = referencePlayer->GetItemByGuid(artifactAura->GetCastItemGUID())) if (ArtifactAppearanceEntry const* artifactAppearance = sArtifactAppearanceStore.LookupEntry(artifact->GetModifier(ITEM_MODIFIER_ARTIFACT_APPEARANCE_ID))) if (artifactAppearance->ArtifactAppearanceSetID == reqValue) - return true; + break; return false; } - case CRITERIA_ADDITIONAL_CONDITION_CURRENCY_AMOUNT_EQUAL: // 209 + case ModifierTreeType::PlayerHasCurrencyEqual: // 209 if (referencePlayer->GetCurrency(reqValue) != secondaryAsset) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_SCENARIO_TYPE: // 211 + case ModifierTreeType::MinimumAverageItemHighWaterMarkForSpec: // 210 NYI + return false; + case ModifierTreeType::PlayerScenarioType: // 211 { Scenario const* scenario = referencePlayer->GetScenario(); if (!scenario) @@ -2615,45 +3000,292 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_ACCOUNT_EXPANSION_EQUAL: // 212 - if (referencePlayer->GetSession()->GetAccountExpansion() != reqValue) + case ModifierTreeType::PlayersAuthExpansionLevelEqualOrGreaterThan: // 212 + if (referencePlayer->GetSession()->GetAccountExpansion() < reqValue) + return false; + break; + case ModifierTreeType::PlayerLastWeek2v2Rating: // 213 NYI + case ModifierTreeType::PlayerLastWeek3v3Rating: // 214 NYI + case ModifierTreeType::PlayerLastWeekRBGRating: // 215 NYI + return false; + case ModifierTreeType::GroupMemberCountFromConnectedRealmEqualOrGreaterThan: // 216 + { + uint32 memberCount = 0; + if (Group const* group = referencePlayer->GetGroup()) + for (GroupReference const* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) + if (itr->GetSource() != referencePlayer && *referencePlayer->m_playerData->VirtualPlayerRealm == *itr->GetSource()->m_playerData->VirtualPlayerRealm) + ++memberCount; + if (memberCount < reqValue) + return false; + break; + } + case ModifierTreeType::ArtifactTraitUnlockedCountEqualOrGreaterThan: // 217 + { + Item const* artifact = referencePlayer->GetItemByEntry(secondaryAsset, ItemSearchLocation::Everywhere); + if (!artifact) + return false; + if (artifact->GetTotalUnlockedArtifactPowers() < reqValue) + return false; + break; + } + case ModifierTreeType::ParagonReputationLevelEqualOrGreaterThan: // 218 + if (referencePlayer->GetReputationMgr().GetParagonLevel(miscValue1) < int32(reqValue)) + return false; + return false; + case ModifierTreeType::GarrisonShipmentIsReady: // 219 NYI + return false; + case ModifierTreeType::PlayerIsInPvpBrawl: // 220 + { + BattlemasterListEntry const* bg = sBattlemasterListStore.LookupEntry(referencePlayer->GetBattlegroundTypeId()); + if (!bg || !(bg->Flags & BATTLEMASTER_LIST_FLAG_BRAWL)) + return false; + break; + } + case ModifierTreeType::ParagonReputationLevelWithFactionEqualOrGreaterThan: // 221 + { + FactionEntry const* faction = sFactionStore.LookupEntry(secondaryAsset); + if (!faction) + return false; + if (referencePlayer->GetReputationMgr().GetParagonLevel(faction->ParagonFactionID) < int32(reqValue)) + return false; + break; + } + case ModifierTreeType::PlayerHasItemWithBonusListFromTreeAndQuality: // 222 + { + std::set<uint32> bonusListIDs = sDB2Manager.GetAllItemBonusTreeBonuses(reqValue); + if (bonusListIDs.empty()) + return false; + + bool bagScanReachedEnd = referencePlayer->ForEachItem(ItemSearchLocation::Everywhere, [&bonusListIDs](Item const* item) + { + bool hasBonus = std::any_of(item->m_itemData->BonusListIDs->begin(), item->m_itemData->BonusListIDs->end(), [&bonusListIDs](int32 bonusListID) + { + return bonusListIDs.find(bonusListID) != bonusListIDs.end(); + }); + return hasBonus ? ItemSearchCallbackResult::Stop : ItemSearchCallbackResult::Continue; + }); + if (bagScanReachedEnd) + return false; + break; + } + case ModifierTreeType::PlayerHasEmptyInventorySlotCountEqualOrGreaterThan: // 223 + if (referencePlayer->GetFreeInventorySlotCount(ItemSearchLocation::Inventory) < reqValue) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_ACHIEVEMENT_GLOBALLY_INCOMPLETED: // 231 + case ModifierTreeType::PlayerHasItemInHistoryOfProgressiveEvent: // 224 NYI + return false; + case ModifierTreeType::PlayerHasArtifactPowerRankCountPurchasedEqualOrGreaterThan: // 225 { - AchievementEntry const* achievement = sAchievementStore.LookupEntry(secondaryAsset); - if (!achievement) + Aura const* artifactAura = referencePlayer->GetAura(ARTIFACTS_ALL_WEAPONS_GENERAL_WEAPON_EQUIPPED_PASSIVE); + if (!artifactAura) + return false; + Item const* artifact = referencePlayer->GetItemByGuid(artifactAura->GetCastItemGUID()); + if (!artifact) return false; - if (sAchievementMgr->IsRealmCompleted(achievement)) + UF::ArtifactPower const* artifactPower = artifact->GetArtifactPower(secondaryAsset); + if (!artifactPower) + return false; + if (artifactPower->PurchasedRank < reqValue) return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_MAIN_HAND_VISIBLE_SUBCLASS: // 232 + case ModifierTreeType::PlayerHasBoosted: // 226 + if (referencePlayer->HasLevelBoosted()) + return false; + break; + case ModifierTreeType::PlayerHasRaceChanged: // 227 + if (referencePlayer->HasRaceChanged()) + return false; + break; + case ModifierTreeType::PlayerHasBeenGrantedLevelsFromRaF: // 228 + if (referencePlayer->HasBeenGrantedLevelsFromRaF()) + return false; + break; + case ModifierTreeType::IsTournamentRealm: // 229 + return false; + case ModifierTreeType::PlayerCanAccessAlliedRaces: // 230 + if (!referencePlayer->GetSession()->CanAccessAlliedRaces()) + return false; + break; + case ModifierTreeType::GroupMemberCountWithAchievementEqualOrLessThan: // 231 { + if (Group const* group = referencePlayer->GetGroup()) + { + uint32 membersWithAchievement = 0; + for (GroupReference const* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) + if (itr->GetSource()->HasAchieved(secondaryAsset)) + ++membersWithAchievement; + + if (membersWithAchievement > reqValue) + return false; + } + // true if no group + break; + } + case ModifierTreeType::PlayerMainhandWeaponType: // 232 + { + UF::VisibleItem const& visibleItem = referencePlayer->m_playerData->VisibleItems[EQUIPMENT_SLOT_MAINHAND]; uint32 itemSubclass = ITEM_SUBCLASS_WEAPON_FIST_WEAPON; - if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(referencePlayer->m_playerData->VisibleItems[EQUIPMENT_SLOT_MAINHAND].ItemID)) - itemSubclass = itemTemplate->GetSubClass(); + if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(visibleItem.ItemID)) + { + if (itemTemplate->GetClass() == ITEM_CLASS_WEAPON) + { + itemSubclass = itemTemplate->GetSubClass(); + + if (ItemModifiedAppearanceEntry const* itemModifiedAppearance = sDB2Manager.GetItemModifiedAppearance(visibleItem.ItemID, visibleItem.ItemAppearanceModID)) + if (ItemModifiedAppearanceExtraEntry const* itemModifiedAppearaceExtra = sItemModifiedAppearanceExtraStore.LookupEntry(itemModifiedAppearance->ID)) + if (itemModifiedAppearaceExtra->DisplayWeaponSubclassID > 0) + itemSubclass = itemModifiedAppearaceExtra->DisplayWeaponSubclassID; + } + } if (itemSubclass != reqValue) return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_OFF_HAND_VISIBLE_SUBCLASS: // 233 + case ModifierTreeType::PlayerOffhandWeaponType: // 233 { + UF::VisibleItem const& visibleItem = referencePlayer->m_playerData->VisibleItems[EQUIPMENT_SLOT_OFFHAND]; uint32 itemSubclass = ITEM_SUBCLASS_WEAPON_FIST_WEAPON; - if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(referencePlayer->m_playerData->VisibleItems[EQUIPMENT_SLOT_OFFHAND].ItemID)) - itemSubclass = itemTemplate->GetSubClass(); + if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(visibleItem.ItemID)) + { + if (itemTemplate->GetClass() == ITEM_CLASS_WEAPON) + { + itemSubclass = itemTemplate->GetSubClass(); + + if (ItemModifiedAppearanceEntry const* itemModifiedAppearance = sDB2Manager.GetItemModifiedAppearance(visibleItem.ItemID, visibleItem.ItemAppearanceModID)) + if (ItemModifiedAppearanceExtraEntry const* itemModifiedAppearaceExtra = sItemModifiedAppearanceExtraStore.LookupEntry(itemModifiedAppearance->ID)) + if (itemModifiedAppearaceExtra->DisplayWeaponSubclassID > 0) + itemSubclass = itemModifiedAppearaceExtra->DisplayWeaponSubclassID; + } + } if (itemSubclass != reqValue) return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_AZERITE_ITEM_LEVEL: // 235 + case ModifierTreeType::PlayerPvpTier: // 234 + { + PvpTierEntry const* pvpTier = sPvpTierStore.LookupEntry(reqValue); + if (!pvpTier) + return false; + if (std::size_t(pvpTier->BracketID) >= referencePlayer->m_activePlayerData->PvpInfo.size()) + return false; + UF::PVPInfo const& pvpInfo = referencePlayer->m_activePlayerData->PvpInfo[pvpTier->BracketID]; + if (pvpTier->ID != pvpInfo.PvpTierID || *pvpInfo.Disqualified) + return false; + break; + } + case ModifierTreeType::PlayerAzeriteLevelEqualOrGreaterThan: // 235 { Item const* heartOfAzeroth = referencePlayer->GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ItemSearchLocation::Everywhere); if (!heartOfAzeroth || heartOfAzeroth->ToAzeriteItem()->GetLevel() < reqValue) return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_DISPLAY_RACE: // 252 + case ModifierTreeType::PlayerIsOnQuestInQuestline: // 236 + { + bool isOnQuest = false; + if (std::unordered_set<QuestLineXQuestEntry const*> const* questLineQuests = sDB2Manager.GetQuestsForQuestLine(reqValue)) + { + isOnQuest = std::any_of(questLineQuests->begin(), questLineQuests->end(), [referencePlayer](QuestLineXQuestEntry const* questLineQuest) + { + return referencePlayer->FindQuestSlot(questLineQuest->QuestID) < MAX_QUEST_LOG_SIZE; + }); + } + if (!isOnQuest) + return false; + break; + } + case ModifierTreeType::PlayerIsQnQuestLinkedToScheduledWorldStateGroup: // 237 + return false; // OBSOLETE (db2 removed) + case ModifierTreeType::PlayerIsInRaidGroup: // 238 + { + Group const* group = referencePlayer->GetGroup(); + if (!group || !group->isRaidGroup()) + return false; + break; + } + case ModifierTreeType::PlayerPvpTierInBracketEqualOrGreaterThan: // 239 + { + if (secondaryAsset >= referencePlayer->m_activePlayerData->PvpInfo.size()) + return false; + UF::PVPInfo const& pvpInfo = referencePlayer->m_activePlayerData->PvpInfo[secondaryAsset]; + PvpTierEntry const* pvpTier = sPvpTierStore.LookupEntry(pvpInfo.PvpTierID); + if (!pvpTier) + return false; + if (pvpTier->Rank < int32(reqValue)) + return false; + break; + } + case ModifierTreeType::PlayerCanAcceptQuestInQuestline: // 240 + { + std::unordered_set<QuestLineXQuestEntry const*> const* questLineQuests = sDB2Manager.GetQuestsForQuestLine(reqValue); + if (!questLineQuests) + return false; + bool canTakeQuest = std::any_of(questLineQuests->begin(), questLineQuests->end(), [referencePlayer](QuestLineXQuestEntry const* questLineQuest) + { + if (Quest const* quest = sObjectMgr->GetQuestTemplate(questLineQuest->QuestID)) + return referencePlayer->CanTakeQuest(quest, false); + return false; + }); + if (!canTakeQuest) + return false; + break; + } + case ModifierTreeType::PlayerHasCompletedQuestline: // 241 + { + std::unordered_set<QuestLineXQuestEntry const*> const* questLineQuests = sDB2Manager.GetQuestsForQuestLine(reqValue); + if (!questLineQuests) + return false; + for (QuestLineXQuestEntry const* questLineQuest : *questLineQuests) + if (!referencePlayer->GetQuestRewardStatus(questLineQuest->QuestID)) + return false; + break; + } + case ModifierTreeType::PlayerHasCompletedQuestlineQuestCount: // 242 + { + std::unordered_set<QuestLineXQuestEntry const*> const* questLineQuests = sDB2Manager.GetQuestsForQuestLine(reqValue); + if (!questLineQuests) + return false; + uint32 completedQuests = 0; + for (QuestLineXQuestEntry const* questLineQuest : *questLineQuests) + if (referencePlayer->GetQuestRewardStatus(questLineQuest->QuestID)) + ++completedQuests; + if (completedQuests < reqValue) + return false; + break; + } + case ModifierTreeType::PlayerHasCompletedPercentageOfQuestline: // 243 + { + std::unordered_set<QuestLineXQuestEntry const*> const* questLineQuests = sDB2Manager.GetQuestsForQuestLine(reqValue); + if (!questLineQuests || questLineQuests->empty()) + return false; + std::size_t completedQuests = 0; + for (QuestLineXQuestEntry const* questLineQuest : *questLineQuests) + if (referencePlayer->GetQuestRewardStatus(questLineQuest->QuestID)) + ++completedQuests; + if (GetPctOf(completedQuests, questLineQuests->size()) < reqValue) + return false; + break; + } + case ModifierTreeType::PlayerHasWarModeEnabled: // 244 + if (!referencePlayer->HasPlayerLocalFlag(PLAYER_LOCAL_FLAG_WAR_MODE)) + return false; + break; + case ModifierTreeType::PlayerIsOnWarModeShard: // 245 + if (!referencePlayer->HasPlayerFlag(PLAYER_FLAGS_WAR_MODE_ACTIVE)) + return false; + break; + case ModifierTreeType::PlayerIsAllowedToToggleWarModeInArea: // 246 + if (!referencePlayer->CanEnableWarModeInArea()) + return false; + break; + case ModifierTreeType::MythicPlusKeystoneLevelEqualOrGreaterThan: // 247 NYI + case ModifierTreeType::MythicPlusCompletedInTime: // 248 NYI + case ModifierTreeType::MythicPlusMapChallengeMode: // 249 NYI + case ModifierTreeType::MythicPlusDisplaySeason: // 250 NYI + case ModifierTreeType::MythicPlusMilestoneSeason: // 251 NYI + return false; + case ModifierTreeType::PlayerVisibleRace: // 252 { CreatureDisplayInfoEntry const* creatureDisplayInfo = sCreatureDisplayInfoStore.LookupEntry(referencePlayer->GetDisplayId()); if (!creatureDisplayInfo) @@ -2665,7 +3297,7 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_TARGET_DISPLAY_RACE: // 253 + case ModifierTreeType::TargetVisibleRace: // 253 { if (!unit) return false; @@ -2679,23 +3311,43 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_AURA_COUNT_EQUAL: // 255 + case ModifierTreeType::FriendshipRepReactionEqual: // 254 + { + FriendshipRepReactionEntry const* friendshipRepReaction = sFriendshipRepReactionStore.LookupEntry(reqValue); + if (!friendshipRepReaction) + return false; + FriendshipReputationEntry const* friendshipReputation = sFriendshipReputationStore.LookupEntry(friendshipRepReaction->FriendshipRepID); + if (!friendshipReputation) + return false; + DB2Manager::FriendshipRepReactionSet const* friendshipReactions = sDB2Manager.GetFriendshipRepReactions(reqValue); + if (!friendshipReactions) + return false; + uint32 rank = referencePlayer->GetReputationRank(friendshipReputation->FactionID); + if (rank >= friendshipReactions->size()) + return false; + auto itr = friendshipReactions->begin(); + std::advance(itr, rank); + if ((*itr)->ID != reqValue) + return false; + break; + } + case ModifierTreeType::PlayerAuraStackCountEqual: // 255 if (referencePlayer->GetAuraCount(secondaryAsset) != reqValue) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_TARGET_AURA_COUNT_EQUAL: // 256 + case ModifierTreeType::TargetAuraStackCountEqual: // 256 if (!unit || unit->GetAuraCount(secondaryAsset) != reqValue) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_AURA_COUNT_GREATER: // 257 + case ModifierTreeType::PlayerAuraStackCountEqualOrGreaterThan: // 257 if (referencePlayer->GetAuraCount(secondaryAsset) < reqValue) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_TARGET_AURA_COUNT_GREATER: // 258 + case ModifierTreeType::TargetAuraStackCountEqualOrGreaterThan: // 258 if (!unit || unit->GetAuraCount(secondaryAsset) < reqValue) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_UNLOCKED_AZERITE_ESSENCE_RANK_LOWER: // 259 + case ModifierTreeType::PlayerHasAzeriteEssenceRankLessThan: // 259 { if (Item const* heartOfAzeroth = referencePlayer->GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ItemSearchLocation::Everywhere)) if (AzeriteItem const* azeriteItem = heartOfAzeroth->ToAzeriteItem()) @@ -2704,7 +3356,7 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 return true; return false; } - case CRITERIA_ADDITIONAL_CONDITION_UNLOCKED_AZERITE_ESSENCE_RANK_EQUAL: // 260 + case ModifierTreeType::PlayerHasAzeriteEssenceRankEqual: // 260 { if (Item const* heartOfAzeroth = referencePlayer->GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ItemSearchLocation::Everywhere)) if (AzeriteItem const* azeriteItem = heartOfAzeroth->ToAzeriteItem()) @@ -2713,7 +3365,7 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 return true; return false; } - case CRITERIA_ADDITIONAL_CONDITION_UNLOCKED_AZERITE_ESSENCE_RANK_GREATER: // 261 + case ModifierTreeType::PlayerHasAzeriteEssenceRankGreaterThan: // 261 { if (Item const* heartOfAzeroth = referencePlayer->GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ItemSearchLocation::Everywhere)) if (AzeriteItem const* azeriteItem = heartOfAzeroth->ToAzeriteItem()) @@ -2722,22 +3374,31 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 return true; return false; } - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_HAS_AURA_EFFECT_INDEX: // 262 + case ModifierTreeType::PlayerHasAuraWithEffectIndex: // 262 if (!referencePlayer->GetAuraEffect(reqValue, secondaryAsset)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_SPECIALIZATION_ROLE: // 263 + case ModifierTreeType::PlayerLootSpecializationMatchesRole: // 263 { ChrSpecializationEntry const* spec = sChrSpecializationStore.LookupEntry(referencePlayer->GetPrimarySpecialization()); if (!spec || spec->Role != int32(reqValue)) return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_LEVEL_120: // 264 - if (referencePlayer->getLevel() != 60) + case ModifierTreeType::PlayerIsAtMaxExpansionLevel: // 264 + if (referencePlayer->getLevel() != GetMaxLevelForExpansion(sWorld->getIntConfig(CONFIG_EXPANSION))) + return false; + break; + case ModifierTreeType::TransmogSource: // 265 + { + ItemModifiedAppearanceEntry const* itemModifiedAppearance = sItemModifiedAppearanceStore.LookupEntry(miscValue2); + if (!itemModifiedAppearance) + return false; + if (itemModifiedAppearance->TransmogSourceTypeEnum != int32(reqValue)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_SELECTED_AZERITE_ESSENCE_RANK_LOWER: // 266 + } + case ModifierTreeType::PlayerHasAzeriteEssenceInSlotAtRankLessThan: // 266 if (Item const* heartOfAzeroth = referencePlayer->GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ItemSearchLocation::Everywhere)) if (AzeriteItem const* azeriteItem = heartOfAzeroth->ToAzeriteItem()) if (UF::SelectedAzeriteEssences const* selectedEssences = azeriteItem->GetSelectedAzeriteEssences()) @@ -2745,7 +3406,7 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 if (essence.AzeriteEssenceID == selectedEssences->AzeriteEssenceID[reqValue] && essence.Rank < secondaryAsset) return true; return false; - case CRITERIA_ADDITIONAL_CONDITION_SELECTED_AZERITE_ESSENCE_RANK_GREATER: // 267 + case ModifierTreeType::PlayerHasAzeriteEssenceInSlotAtRankGreaterThan: // 267 if (Item const* heartOfAzeroth = referencePlayer->GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH, ItemSearchLocation::Everywhere)) if (AzeriteItem const* azeriteItem = heartOfAzeroth->ToAzeriteItem()) if (UF::SelectedAzeriteEssences const* selectedEssences = azeriteItem->GetSelectedAzeriteEssences()) @@ -2753,7 +3414,7 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 if (essence.AzeriteEssenceID == selectedEssences->AzeriteEssenceID[reqValue] && essence.Rank > secondaryAsset) return true; return false; - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_LEVEL_IN_RANGE_CT: // 268 + case ModifierTreeType::PlayerLevelWithinContentTuning: // 268 { uint8 level = referencePlayer->getLevel(); if (Optional<ContentTuningLevels> levels = sDB2Manager.GetContentTuningData(reqValue, 0)) @@ -2764,7 +3425,7 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 } return false; } - case CRITERIA_ADDITIONAL_CONDITION_TARGET_LEVEL_IN_RANGE_CT: // 269 + case ModifierTreeType::TargetLevelWithinContentTuning: // 269 { if (!unit) return false; @@ -2777,14 +3438,23 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 } return false; } - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_LEVEL_GREATER_CT: // 272 + case ModifierTreeType::PlayerIsScenarioInitiator: // 270 NYI + return false; + case ModifierTreeType::PlayerHasCompletedQuestOrIsOnQuest: // 271 + { + QuestStatus status = referencePlayer->GetQuestStatus(reqValue); + if (status == QUEST_STATUS_NONE || status == QUEST_STATUS_FAILED) + return false; + break; + } + case ModifierTreeType::PlayerLevelWithinOrAboveContentTuning: // 272 { uint8 level = referencePlayer->getLevel(); if (Optional<ContentTuningLevels> levels = sDB2Manager.GetContentTuningData(reqValue, 0)) return secondaryAsset ? level >= levels->MinLevelWithDelta : level >= levels->MinLevel; return false; } - case CRITERIA_ADDITIONAL_CONDITION_TARGET_LEVEL_GREATER_CT: // 273 + case ModifierTreeType::TargetLevelWithinOrAboveContentTuning: // 273 { if (!unit) return false; @@ -2793,22 +3463,101 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 return secondaryAsset ? level >= levels->MinLevelWithDelta : level >= levels->MinLevel; return false; } - case CRITERIA_ADDITIONAL_CONDITION_MAP_OR_COSMETIC_MAP: // 280 + case ModifierTreeType::PlayerLevelWithinOrAboveLevelRange: // 274 NYI + case ModifierTreeType::TargetLevelWithinOrAboveLevelRange: // 275 NYI + return false; + case ModifierTreeType::MaxJailersTowerLevelEqualOrGreaterThan: // 276 + if (referencePlayer->m_activePlayerData->JailersTowerLevelMax < int32(reqValue)) + return false; + break; + case ModifierTreeType::GroupedWithRaFRecruit: // 277 + { + Group const* group = referencePlayer->GetGroup(); + if (!group) + return false; + for (GroupReference const* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) + if (itr->GetSource()->GetSession()->GetRecruiterId() == referencePlayer->GetSession()->GetAccountId()) + return true; + return false; + } + case ModifierTreeType::GroupedWithRaFRecruiter: // 278 + { + Group const* group = referencePlayer->GetGroup(); + if (!group) + return false; + for (GroupReference const* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) + if (itr->GetSource()->GetSession()->GetAccountId() == referencePlayer->GetSession()->GetRecruiterId()) + return true; + return false; + } + case ModifierTreeType::PlayerSpecialization: // 279 + if (referencePlayer->GetPrimarySpecialization() != reqValue) + return false; + break; + case ModifierTreeType::PlayerMapOrCosmeticChildMap: // 280 { MapEntry const* map = referencePlayer->GetMap()->GetEntry(); if (map->ID != reqValue && map->CosmeticParentMapID != int32(reqValue)) return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_COVENANT: // 288 + case ModifierTreeType::PlayerCanAccessShadowlandsPrepurchaseContent: // 281 + if (referencePlayer->GetSession()->GetAccountExpansion() < EXPANSION_SHADOWLANDS) + return false; + break; + case ModifierTreeType::PlayerHasEntitlement: // 282 NYI + case ModifierTreeType::PlayerIsInPartySyncGroup: // 283 NYI + case ModifierTreeType::QuestHasPartySyncRewards: // 284 NYI + case ModifierTreeType::HonorGainSource: // 285 NYI + case ModifierTreeType::JailersTowerActiveFloorIndexEqualOrGreaterThan: // 286 NYI + case ModifierTreeType::JailersTowerActiveFloorDifficultyEqualOrGreaterThan: // 287 NYI + return false; + case ModifierTreeType::PlayerCovenant: // 288 if (referencePlayer->m_playerData->CovenantID != int32(reqValue)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_SOULBIND: // 291 + case ModifierTreeType::HasTimeEventPassed: // 289 + { + time_t eventTimestamp = GameTime::GetGameTime(); + switch (reqValue) + { + case 111: // Battle for Azeroth Season 4 Start + eventTimestamp = time_t(1579618800); // January 21, 2020 8:00 + break; + case 120: // Patch 9.0.1 + eventTimestamp = time_t(1602601200); // October 13, 2020 8:00 + break; + case 121: // Shadowlands Season 1 Start + eventTimestamp = time_t(1607439600); // December 8, 2020 8:00 + break; + case 123: // Shadowlands Season 1 End + // timestamp = unknown + break;; + case 149: // Shadowlands Season 2 End + // timestamp = unknown + break; + default: + break; + } + if (GameTime::GetGameTime() < eventTimestamp) + return false; + break; + } + case ModifierTreeType::GarrisonHasPermanentTalent: // 290 NYI + return false; + case ModifierTreeType::HasActiveSoulbind: // 291 if (referencePlayer->m_playerData->SoulbindID != int32(reqValue)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_AREA_OR_ZONE_IN_GROUP: // 293 + case ModifierTreeType::HasMemorizedSpell: // 292 NYI + return false; + case ModifierTreeType::PlayerHasAPACSubscriptionReward_2020: // 293 + case ModifierTreeType::PlayerHasTBCCDEWarpStalker_Mount: // 294 + case ModifierTreeType::PlayerHasTBCCDEDarkPortal_Toy: // 295 + case ModifierTreeType::PlayerHasTBCCDEPathOfIllidan_Toy: // 296 + case ModifierTreeType::PlayerHasImpInABallToySubscriptionReward: // 297 + return false; + case ModifierTreeType::PlayerIsInAreaGroup: // 298 { std::vector<uint32> areas = sDB2Manager.GetAreasForGroup(reqValue); if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(referencePlayer->GetAreaId())) @@ -2817,15 +3566,30 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 return true; return false; } - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_IN_SPECIFIC_CHROMIE_TIME: // 300 + case ModifierTreeType::TargetIsInAreaGroup: // 299 + { + if (!unit) + return false; + std::vector<uint32> areas = sDB2Manager.GetAreasForGroup(reqValue); + if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(unit->GetAreaId())) + for (uint32 areaInGroup : areas) + if (areaInGroup == area->ID || areaInGroup == area->ParentAreaID) + return true; + return false; + } + case ModifierTreeType::PlayerIsInChromieTime: // 300 if (referencePlayer->m_activePlayerData->UiChromieTimeExpansionID != int32(reqValue)) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_IN_ANY_CHROMIE_TIME: // 301 + case ModifierTreeType::PlayerIsInAnyChromieTime: // 301 if (referencePlayer->m_activePlayerData->UiChromieTimeExpansionID == 0) return false; break; - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_RUNEFORGE_LEGENDARY_KNOWN: // 303 + case ModifierTreeType::ItemIsAzeriteArmor: // 302 + if (!sDB2Manager.GetAzeriteEmpoweredItem(miscValue1)) + return false; + break; + case ModifierTreeType::PlayerHasRuneforgePower: // 303 { uint32 block = reqValue / 32; if (block >= referencePlayer->m_activePlayerData->RuneforgePowers.size()) @@ -2834,7 +3598,29 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 uint32 bit = reqValue % 32; return referencePlayer->m_activePlayerData->RuneforgePowers[block] & (1 << bit); } - case CRITERIA_ADDITIONAL_CONDITION_SHAPESHIFT_FORM_CUSTOMIZATION_DISPLAY: // 308 + case ModifierTreeType::PlayerInChromieTimeForScaling: // 304 + if (!(referencePlayer->m_playerData->CtrOptions->ContentTuningConditionMask & 1)) + return false; + break; + case ModifierTreeType::IsRaFRecruit: // 305 + if (!referencePlayer->GetSession()->GetRecruiterId()) + return false; + break; + case ModifierTreeType::AllPlayersInGroupHaveAchievement: // 306 + { + if (Group const* group = referencePlayer->GetGroup()) + { + for (GroupReference const* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) + if (!itr->GetSource()->HasAchieved(reqValue)) + return false; + } + else if (!referencePlayer->HasAchieved(reqValue)) + return false; + break; + } + case ModifierTreeType::PlayerHasSoulbindConduitRankEqualOrGreaterThan: // 307 NYI + return false; + case ModifierTreeType::PlayerSpellShapeshiftFormCreatureDisplayInfoSelection: // 308 { ShapeshiftFormModelData const* formModelData = sDB2Manager.GetShapeshiftFormModelData(referencePlayer->getRace(), referencePlayer->GetNativeSex(), secondaryAsset); if (!formModelData) @@ -2850,12 +3636,45 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 return false; break; } - case CRITERIA_ADDITIONAL_CONDITION_SOURCE_FLYING: // 311 + case ModifierTreeType::PlayerSoulbindConduitCountAtRankEqualOrGreaterThan: // 309 NYI + return false; + case ModifierTreeType::PlayerIsRestrictedAccount: // 310 + return false; + case ModifierTreeType::PlayerIsFlying: // 311 if (!referencePlayer->IsFlying()) return false; break; - default: + case ModifierTreeType::PlayerScenarioIsLastStep: // 312 + { + Scenario const* scenario = referencePlayer->GetScenario(); + if (!scenario) + return false; + if (scenario->GetStep() != scenario->GetLastStep()) + return false; break; + } + case ModifierTreeType::PlayerHasWeeklyRewardsAvailable: // 313 + if (!*referencePlayer->m_activePlayerData->WeeklyRewardsPeriodSinceOrigin) + return false; + break; + case ModifierTreeType::TargetCovenant: // 314 + if (!unit || !unit->IsPlayer()) + return false; + if (unit->ToPlayer()->m_playerData->CovenantID != int32(reqValue)) + return false; + break; + case ModifierTreeType::PlayerHasTBCCollectorsEdition: // 315 + case ModifierTreeType::PlayerHasWrathCollectorsEdition: // 316 + return false; + case ModifierTreeType::GarrisonTalentResearchedAndAtRankEqualOrGreaterThan: // 317 NYI + case ModifierTreeType::CurrencySpentOnGarrisonTalentResearchEqualOrGreaterThan: // 318 NYI + case ModifierTreeType::RenownCatchupActive: // 319 NYI + case ModifierTreeType::RapidRenownCatchupActive: // 320 NYI + case ModifierTreeType::PlayerMythicPlusRatingEqualOrGreaterThan: // 321 NYI + case ModifierTreeType::PlayerMythicPlusRunCountInCurrentExpansionEqualOrGreaterThan: // 322 NYI + return false; + default: + return false; } return true; } diff --git a/src/server/game/BattlePets/BattlePetMgr.cpp b/src/server/game/BattlePets/BattlePetMgr.cpp index fc02c8db8e8..5fd954f931f 100644 --- a/src/server/game/BattlePets/BattlePetMgr.cpp +++ b/src/server/game/BattlePets/BattlePetMgr.cpp @@ -359,6 +359,16 @@ uint8 BattlePetMgr::GetPetCount(uint32 species) const })); } +uint32 BattlePetMgr::GetPetUniqueSpeciesCount() const +{ + std::set<uint32> speciesIds; + std::transform(_pets.begin(), _pets.end(), std::inserter(speciesIds, speciesIds.end()), [](std::pair<uint64 const, BattlePet> const& pet) + { + return pet.second.PacketInfo.Species; + }); + return speciesIds.size(); +} + void BattlePetMgr::UnlockSlot(uint8 slot) { if (!_slots[slot].Locked) diff --git a/src/server/game/BattlePets/BattlePetMgr.h b/src/server/game/BattlePets/BattlePetMgr.h index edf0937ea76..49ed9edc23f 100644 --- a/src/server/game/BattlePets/BattlePetMgr.h +++ b/src/server/game/BattlePets/BattlePetMgr.h @@ -96,7 +96,7 @@ public: void CalculateStats(); WorldPackets::BattlePet::BattlePet PacketInfo; - BattlePetSaveInfo SaveInfo; + BattlePetSaveInfo SaveInfo = BATTLE_PET_UNCHANGED; }; explicit BattlePetMgr(WorldSession* owner); @@ -114,6 +114,7 @@ public: void RemovePet(ObjectGuid guid); uint8 GetPetCount(uint32 species) const; + uint32 GetPetUniqueSpeciesCount() const; WorldPackets::BattlePet::BattlePetSlot* GetSlot(uint8 slot) { return slot < _slots.size() ? &_slots[slot] : nullptr; } void UnlockSlot(uint8 slot); @@ -134,6 +135,8 @@ public: void SendUpdates(std::vector<std::reference_wrapper<BattlePet>> pets, bool petAdded); void SendError(BattlePetError error, uint32 creatureId); + bool HasJournalLock() const { return true; } + private: WorldSession* _owner; uint16 _trapLevel = 0; diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp index 8666e5ec3e3..ee13cf121bd 100644 --- a/src/server/game/DataStores/DB2Stores.cpp +++ b/src/server/game/DataStores/DB2Stores.cpp @@ -2393,6 +2393,17 @@ std::set<uint32> DB2Manager::GetDefaultItemBonusTree(uint32 itemId, ItemContext return bonusListIDs; } +std::set<uint32> DB2Manager::GetAllItemBonusTreeBonuses(uint32 itemBonusTreeId) const +{ + std::set<uint32> bonusListIDs; + VisitItemBonusTree(itemBonusTreeId, true, [&bonusListIDs](ItemBonusTreeNodeEntry const* bonusTreeNode) + { + if (bonusTreeNode->ChildItemBonusListID) + bonusListIDs.insert(bonusTreeNode->ChildItemBonusListID); + }); + return bonusListIDs; +} + void LoadAzeriteEmpoweredItemUnlockMappings(std::unordered_map<int32, std::vector<AzeriteUnlockMappingEntry const*>> const& azeriteUnlockMappingsBySet, uint32 itemId) { auto itemIdRange = _itemToBonusTree.equal_range(itemId); diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h index 63ca97a66fa..ded5f83d646 100644 --- a/src/server/game/DataStores/DB2Stores.h +++ b/src/server/game/DataStores/DB2Stores.h @@ -373,6 +373,7 @@ public: ItemBonusList const* GetItemBonusList(uint32 bonusListId) const; uint32 GetItemBonusListForItemLevelDelta(int16 delta) const; std::set<uint32> GetDefaultItemBonusTree(uint32 itemId, ItemContext itemContext) const; + std::set<uint32> GetAllItemBonusTreeBonuses(uint32 itemBonusTreeId) const; ItemChildEquipmentEntry const* GetItemChildEquipment(uint32 itemId) const; ItemClassEntry const* GetItemClassByOldEnum(uint32 itemClass) const; bool HasItemCurrencyCost(uint32 itemId) const; diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index 875576fe4c5..58ed8877447 100644 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -104,6 +104,8 @@ enum AchievementFlags ACHIEVEMENT_FLAG_TRACKING_FLAG = 0x00100000, // hidden tracking flag, sent to client in all cases except completion announcements }; +uint32 constexpr ACHIVEMENT_CATEGORY_PET_BATTLES = 15117; + enum AreaFlags { AREA_FLAG_SNOW = 0x00000001, // snow (only Dun Morogh, Naxxramas, Razorfen Downs and Winterspring) @@ -244,321 +246,6 @@ enum class CorruptionEffectsFlag DEFINE_ENUM_FLAG(CorruptionEffectsFlag); -enum CriteriaAdditionalCondition -{ - CRITERIA_ADDITIONAL_CONDITION_SOURCE_DRUNK_VALUE = 1, - CRITERIA_ADDITIONAL_CONDITION_SOURCE_PLAYER_CONDITION = 2, - CRITERIA_ADDITIONAL_CONDITION_ITEM_LEVEL = 3, - CRITERIA_ADDITIONAL_CONDITION_TARGET_CREATURE_ENTRY = 4, - CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_PLAYER = 5, - CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_DEAD = 6, - CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_ENEMY = 7, - CRITERIA_ADDITIONAL_CONDITION_SOURCE_HAS_AURA = 8, - CRITERIA_ADDITIONAL_CONDITION_SOURCE_HAS_AURA_TYPE = 9, - CRITERIA_ADDITIONAL_CONDITION_TARGET_HAS_AURA = 10, - CRITERIA_ADDITIONAL_CONDITION_TARGET_HAS_AURA_TYPE = 11, - CRITERIA_ADDITIONAL_CONDITION_SOURCE_AURA_STATE = 12, - CRITERIA_ADDITIONAL_CONDITION_TARGET_AURA_STATE = 13, - CRITERIA_ADDITIONAL_CONDITION_ITEM_QUALITY_MIN = 14, - CRITERIA_ADDITIONAL_CONDITION_ITEM_QUALITY_EQUALS = 15, - CRITERIA_ADDITIONAL_CONDITION_SOURCE_IS_ALIVE = 16, - CRITERIA_ADDITIONAL_CONDITION_SOURCE_AREA_OR_ZONE = 17, - CRITERIA_ADDITIONAL_CONDITION_TARGET_AREA_OR_ZONE = 18, - //CRITERIA_ADDITIONAL_CONDITION_UNK_19 = 19, - CRITERIA_ADDITIONAL_CONDITION_MAP_DIFFICULTY_OLD = 20, - CRITERIA_ADDITIONAL_CONDITION_TARGET_CREATURE_YIELDS_XP = 21, // NYI - CRITERIA_ADDITIONAL_CONDITION_SOURCE_LEVEL_ABOVE_TARGET = 22, - CRITERIA_ADDITIONAL_CONDITION_SOURCE_LEVEL_EQUAL_TARGET = 23, - CRITERIA_ADDITIONAL_CONDITION_ARENA_TYPE = 24, - CRITERIA_ADDITIONAL_CONDITION_SOURCE_RACE = 25, - CRITERIA_ADDITIONAL_CONDITION_SOURCE_CLASS = 26, - CRITERIA_ADDITIONAL_CONDITION_TARGET_RACE = 27, - CRITERIA_ADDITIONAL_CONDITION_TARGET_CLASS = 28, - CRITERIA_ADDITIONAL_CONDITION_MAX_GROUP_MEMBERS = 29, - CRITERIA_ADDITIONAL_CONDITION_TARGET_CREATURE_TYPE = 30, - CRITERIA_ADDITIONAL_CONDITION_TARGET_CREATURE_FAMILY = 31, - CRITERIA_ADDITIONAL_CONDITION_SOURCE_MAP = 32, - CRITERIA_ADDITIONAL_CONDITION_CLIENT_VERSION = 33, - CRITERIA_ADDITIONAL_CONDITION_BATTLE_PET_TEAM_LEVEL = 34, - CRITERIA_ADDITIONAL_CONDITION_NOT_IN_GROUP = 35, - CRITERIA_ADDITIONAL_CONDITION_IN_GROUP = 36, - CRITERIA_ADDITIONAL_CONDITION_MIN_PERSONAL_RATING = 37, // NYI - CRITERIA_ADDITIONAL_CONDITION_TITLE_BIT_INDEX = 38, - CRITERIA_ADDITIONAL_CONDITION_SOURCE_LEVEL = 39, - CRITERIA_ADDITIONAL_CONDITION_TARGET_LEVEL = 40, - CRITERIA_ADDITIONAL_CONDITION_SOURCE_ZONE = 41, - CRITERIA_ADDITIONAL_CONDITION_TARGET_ZONE = 42, - CRITERIA_ADDITIONAL_CONDITION_SOURCE_HEALTH_PCT_LOWER = 43, - CRITERIA_ADDITIONAL_CONDITION_SOURCE_HEALTH_PCT_GREATER = 44, - CRITERIA_ADDITIONAL_CONDITION_SOURCE_HEALTH_PCT_EQUAL = 45, - CRITERIA_ADDITIONAL_CONDITION_TARGET_HEALTH_PCT_LOWER = 46, - CRITERIA_ADDITIONAL_CONDITION_TARGET_HEALTH_PCT_GREATER = 47, - CRITERIA_ADDITIONAL_CONDITION_TARGET_HEALTH_PCT_EQUAL = 48, - CRITERIA_ADDITIONAL_CONDITION_SOURCE_HEALTH_LOWER = 49, - CRITERIA_ADDITIONAL_CONDITION_SOURCE_HEALTH_GREATER = 50, - CRITERIA_ADDITIONAL_CONDITION_SOURCE_HEALTH_EQUAL = 51, - CRITERIA_ADDITIONAL_CONDITION_TARGET_HEALTH_LOWER = 52, - CRITERIA_ADDITIONAL_CONDITION_TARGET_HEALTH_GREATER = 53, - CRITERIA_ADDITIONAL_CONDITION_TARGET_HEALTH_EQUAL = 54, - CRITERIA_ADDITIONAL_CONDITION_TARGET_PLAYER_CONDITION = 55, - CRITERIA_ADDITIONAL_CONDITION_MIN_ACHIEVEMENT_POINTS = 56, - CRITERIA_ADDITIONAL_CONDITION_IN_LFG_DUNGEON = 57, - CRITERIA_ADDITIONAL_CONDITION_IN_LFG_RANDOM_DUNGEON = 58, - CRITERIA_ADDITIONAL_CONDITION_IN_LFG_FIRST_RANDOM_DUNGEON = 59, - //CRITERIA_ADDITIONAL_CONDITION_UNK_60 = 60, // NYI - CRITERIA_ADDITIONAL_CONDITION_REQUIRES_GUILD_GROUP = 61, // NYI - CRITERIA_ADDITIONAL_CONDITION_GUILD_REPUTATION = 62, - CRITERIA_ADDITIONAL_CONDITION_RATED_BATTLEGROUND = 63, // NYI - CRITERIA_ADDITIONAL_CONDITION_RATED_BATTLEGROUND_RATING = 64, - CRITERIA_ADDITIONAL_CONDITION_PROJECT_RARITY = 65, - CRITERIA_ADDITIONAL_CONDITION_PROJECT_RACE = 66, - CRITERIA_ADDITIONAL_CONDITION_WORLD_STATE_EXPRESSION = 67, - CRITERIA_ADDITIONAL_CONDITION_MAP_DIFFICULTY = 68, - CRITERIA_ADDITIONAL_CONDITION_SOURCE_LEVEL_GREATER = 69, - CRITERIA_ADDITIONAL_CONDITION_TARGET_LEVEL_GREATER = 70, - CRITERIA_ADDITIONAL_CONDITION_SOURCE_LEVEL_LOWER = 71, - CRITERIA_ADDITIONAL_CONDITION_TARGET_LEVEL_LOWER = 72, - CRITERIA_ADDITIONAL_CONDITION_MODIFIER_TREE = 73, - CRITERIA_ADDITIONAL_CONDITION_SCENARIO_ID = 74, - CRITERIA_ADDITIONAL_CONDITION_THE_TILLERS_REPUTATION = 75, - CRITERIA_ADDITIONAL_CONDITION_PET_BATTLE_ACHIEVEMENT_POINTS = 76, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_77 = 77, // NYI - CRITERIA_ADDITIONAL_CONDITION_BATTLE_PET_FAMILY = 78, // NYI - CRITERIA_ADDITIONAL_CONDITION_BATTLE_PET_HEALTH_PCT = 79, // NYI - CRITERIA_ADDITIONAL_CONDITION_GUILD_GROUP_MEMBERS = 80, // NYI - CRITERIA_ADDITIONAL_CONDITION_BATTLE_PET_ENTRY = 81, // NYI - CRITERIA_ADDITIONAL_CONDITION_SCENARIO_STEP_INDEX = 82, - CRITERIA_ADDITIONAL_CONDITION_CHALLENGE_MODE_MEDAL = 83, // NYI - CRITERIA_ADDITIONAL_CONDITION_IS_ON_QUEST = 84, - CRITERIA_ADDITIONAL_CONDITION_EXALTED_WITH_FACTION = 85, // NYI - CRITERIA_ADDITIONAL_CONDITION_HAS_ACHIEVEMENT = 86, - CRITERIA_ADDITIONAL_CONDITION_HAS_ACHIEVEMENT_ON_CHARACTER = 87, // NYI - CRITERIA_ADDITIONAL_CONDITION_CLOUD_SERPENT_REPUTATION = 88, - CRITERIA_ADDITIONAL_CONDITION_BATTLE_PET_BREED_QUALITY_ID = 89, // NYI - CRITERIA_ADDITIONAL_CONDITION_PET_BATTLE_IS_PVP = 90, // NYI - CRITERIA_ADDITIONAL_CONDITION_BATTLE_PET_SPECIES = 91, - CRITERIA_ADDITIONAL_CONDITION_ACTIVE_EXPANSION = 92, - //CRITERIA_ADDITIONAL_CONDITION_UNK_93 = 93, // NYI - CRITERIA_ADDITIONAL_CONDITION_FRIENDSHIP_REP_REACTION = 94, // NYI - CRITERIA_ADDITIONAL_CONDITION_FACTION_STANDING = 95, - CRITERIA_ADDITIONAL_CONDITION_ITEM_CLASS_AND_SUBCLASS = 96, // NYI - CRITERIA_ADDITIONAL_CONDITION_SOURCE_SEX = 97, - CRITERIA_ADDITIONAL_CONDITION_SOURCE_NATIVE_SEX = 98, - CRITERIA_ADDITIONAL_CONDITION_SKILL = 99, - //CRITERIA_ADDITIONAL_CONDITION_UNK_100 = 100, // NYI - CRITERIA_ADDITIONAL_CONDITION_NORMAL_PHASE_SHIFT = 101, - CRITERIA_ADDITIONAL_CONDITION_IN_PHASE = 102, - CRITERIA_ADDITIONAL_CONDITION_NOT_IN_PHASE = 103, - CRITERIA_ADDITIONAL_CONDITION_HAS_SPELL = 104, - CRITERIA_ADDITIONAL_CONDITION_ITEM_COUNT = 105, - CRITERIA_ADDITIONAL_CONDITION_ACCOUNT_EXPANSION = 106, - CRITERIA_ADDITIONAL_CONDITION_SOURCE_HAS_AURA_LABEL = 107, // NYI, SpellLabel - //CRITERIA_ADDITIONAL_CONDITION_UNK_108 = 108, // NYI - CRITERIA_ADDITIONAL_CONDITION_TIME_IN_RANGE = 109, // NYI, packed time between asset and secondaryAsset - CRITERIA_ADDITIONAL_CONDITION_REWARDED_QUEST = 110, - CRITERIA_ADDITIONAL_CONDITION_COMPLETED_QUEST = 111, - CRITERIA_ADDITIONAL_CONDITION_COMPLETED_QUEST_OBJECTIVE = 112, // QuestObjectiveID - CRITERIA_ADDITIONAL_CONDITION_EXPLORED_AREA = 113, - CRITERIA_ADDITIONAL_CONDITION_ITEM_COUNT_INCLUDING_BANK = 114, - //CRITERIA_ADDITIONAL_CONDITION_UNK_115 = 115, // NYI - CRITERIA_ADDITIONAL_CONDITION_SOURCE_PVP_FACTION_INDEX = 116, - CRITERIA_ADDITIONAL_CONDITION_LFG_VALUE_EQUAL = 117, - CRITERIA_ADDITIONAL_CONDITION_LFG_VALUE_GREATER = 118, - CRITERIA_ADDITIONAL_CONDITION_CURRENCY_AMOUNT = 119, - //CRITERIA_ADDITIONAL_CONDITION_UNK_120 = 120, // NYI - CRITERIA_ADDITIONAL_CONDITION_CURRENCY_TRACKED_AMOUNT = 121, - CRITERIA_ADDITIONAL_CONDITION_MAP_INSTANCE_TYPE = 122, - CRITERIA_ADDITIONAL_CONDITION_MENTOR = 123, - //CRITERIA_ADDITIONAL_CONDITION_UNK_124 = 124, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_125 = 125, // NYI - CRITERIA_ADDITIONAL_CONDITION_GARRISON_LEVEL_ABOVE = 126, // asset: garrLevel, secondaryAsset: garrType - CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWERS_ABOVE_LEVEL = 127, // asset: count, secondaryAsset: followerLevel, tertiaryAsset: garrType - CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWERS_ABOVE_QUALITY = 128, // asset: count, secondaryAsset: followerQuality, tertiaryAsset: garrType - CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_ABOVE_LEVEL_WITH_ABILITY = 129, // asset: followerLevel, secondaryAsset: ability, tertiaryAsset: garrType - CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_ABOVE_LEVEL_WITH_TRAIT = 130, // asset: followerLevel, secondaryAsset: ability, tertiaryAsset: garrType (same as above but ability must have GARRISON_ABILITY_FLAG_TRAIT) - CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_WITH_ABILITY_IN_BUILDING = 131, // asset: ability, secondaryAsset: buildingType, tertiaryAsset: garrType - CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_WITH_TRAIT_IN_BUILDING = 132, // asset: ability, secondaryAsset: buildingType, tertiaryAsset: garrType - CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_ABOVE_LEVEL_IN_BUILDING = 133, // asset: followerLevel, secondaryAsset: buildingType, tertiaryAsset: garrType - CRITERIA_ADDITIONAL_CONDITION_GARRISON_BUILDING_ABOVE_LEVEL = 134, // asset: buildingType, secondaryAsset: buildingLevel, tertiaryAsset: garrType - CRITERIA_ADDITIONAL_CONDITION_GARRISON_BLUEPRINT = 135, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_136 = 136, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_137 = 137, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_138 = 138, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_139 = 139, // NYI - CRITERIA_ADDITIONAL_CONDITION_GARRISON_BUILDING_INACTIVE = 140, - //CRITERIA_ADDITIONAL_CONDITION_UNK_141 = 141, // NYI - CRITERIA_ADDITIONAL_CONDITION_GARRISON_BUILDING_EQUAL_LEVEL = 142, // asset: buildingType, secondaryAsset: buildingLevel, tertiaryAsset: garrType - CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_WITH_ABILITY= 143, // asset: ability, secondaryAsset: garrType - CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_WITH_TRAIT = 144, // asset: ability, secondaryAsset: garrType - CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_ABOVE_QUALITY_WOD = 145, // asset: followerQuality - CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_EQUAL_LEVEL = 146, // asset: followerLevel, secondaryAsset: garrType - CRITERIA_ADDITIONAL_CONDITION_GARRISON_RARE_MISSION = 147, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_148 = 148, // NYI - CRITERIA_ADDITIONAL_CONDITION_GARRISON_BUILDING_LEVEL = 149, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_150 = 150, // NYI - CRITERIA_ADDITIONAL_CONDITION_BATTLE_PET_SPECIES_IN_TEAM = 151, // asset: count, secondaryAsset: battlePetSpeciesId - CRITERIA_ADDITIONAL_CONDITION_BATTLE_PET_FAMILY_IN_TEAM = 152, // asset: count, secondaryAsset: battlePetFamily - //CRITERIA_ADDITIONAL_CONDITION_UNK_153 = 153, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_154 = 154, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_155 = 155, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_156 = 156, // NYI - CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_ID = 157, // follower with id, in any garrison - CRITERIA_ADDITIONAL_CONDITION_QUEST_OBJECTIVE_PROGRESS_EQUAL= 158, // NYI asset: questObjectiveId, secondaryAsset: progress - CRITERIA_ADDITIONAL_CONDITION_QUEST_OBJECTIVE_PROGRESS_ABOVE= 159, // NYI asset: questObjectiveId, secondaryAsset: progress - //CRITERIA_ADDITIONAL_CONDITION_UNK_160 = 160, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_161 = 161, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_162 = 162, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_163 = 163, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_164 = 164, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_165 = 165, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_166 = 166, // NYI - CRITERIA_ADDITIONAL_CONDITION_GARRISON_MISSION_TYPE = 167, // NYI - CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_ABOVE_ITEM_LEVEL = 168, // asset: followerItemLevel - CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWERS_ABOVE_ITEM_LEVEL = 169, // asset: count, secondaryAsset: followerItemLevel, tertiaryAsset: garrType - CRITERIA_ADDITIONAL_CONDITION_GARRISON_LEVEL_EQUAL = 170, // asset: count - CRITERIA_ADDITIONAL_CONDITION_GARRISON_GROUP_SIZE = 171, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_172 = 172, // NYI something to do with currency but only used on criterias that require the same currency - CRITERIA_ADDITIONAL_CONDITION_TARGETING_CORPSE = 173, - //CRITERIA_ADDITIONAL_CONDITION_UNK_174 = 174, // NYI - CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWERS_LEVEL_EQUAL= 175, // asset: count, secondaryAsset: followerLevel, tertiaryAsset: garrType - CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_ID_IN_BUILDING = 176, // asset: followerId, secondaryAsset: buildingType - //CRITERIA_ADDITIONAL_CONDITION_UNK_177 = 177, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_178 = 178, // NYI - CRITERIA_ADDITIONAL_CONDITION_WORLD_PVP_AREA = 179, // NYI - CRITERIA_ADDITIONAL_CONDITION_NON_OWN_GARRISON = 180, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_181 = 181, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_182 = 183, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_183 = 183, // NYI - CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWERS_ITEM_LEVEL_ABOVE = 184, - //CRITERIA_ADDITIONAL_CONDITION_UNK_185 = 185, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_186 = 186, // NYI - CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_TYPE = 187, // NYI - CRITERIA_ADDITIONAL_CONDITION_USED_LEVEL_BOOST_LESS_THAN_HOURS_AGO = 188, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_189 = 189, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_190 = 190, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_191 = 191, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_192 = 192, // NYI - CRITERIA_ADDITIONAL_CONDITION_HONOR_LEVEL = 193, - CRITERIA_ADDITIONAL_CONDITION_PRESTIGE_LEVEL = 194, - //CRITERIA_ADDITIONAL_CONDITION_UNK_195 = 195, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_196 = 196, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_197 = 197, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_198 = 198, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_198 = 199, // NYI - CRITERIA_ADDITIONAL_CONDITION_ITEM_MODIFIED_APPEARANCE = 200, - CRITERIA_ADDITIONAL_CONDITION_GARRISON_SELECTED_TALENT = 201, // NYI asset: garrTalentId (talent selected, research timer doesn't matter) - CRITERIA_ADDITIONAL_CONDITION_GARRISON_RESEARCHED_TALENT = 202, // NYI asset: garrTalentId (talent selected, research must be finished) - CRITERIA_ADDITIONAL_CONDITION_HAS_CHARACTER_RESTRICTIONS = 203, - //CRITERIA_ADDITIONAL_CONDITION_UNK_204 = 204, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_205 = 205, // NYI - CRITERIA_ADDITIONAL_CONDITION_QUEST_INFO_ID = 206, - CRITERIA_ADDITIONAL_CONDITION_GARRISON_RESEARCHING_TALENT = 207, // NYI asset: garrTalentId (talent selected, research must be in progress) - CRITERIA_ADDITIONAL_CONDITION_ARTIFACT_APPEARANCE_SET_USED = 208, - CRITERIA_ADDITIONAL_CONDITION_CURRENCY_AMOUNT_EQUAL = 209, - //CRITERIA_ADDITIONAL_CONDITION_UNK_210 = 210, // NYI - CRITERIA_ADDITIONAL_CONDITION_SCENARIO_TYPE = 211, - CRITERIA_ADDITIONAL_CONDITION_ACCOUNT_EXPANSION_EQUAL = 212, - //CRITERIA_ADDITIONAL_CONDITION_UNK_213 = 213, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_214 = 214, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_215 = 215, // NYI - CRITERIA_ADDITIONAL_CONDITION_CHALLENGE_MODE_MEDAL_2 = 216, // NYI keystone master, asset = 3 - //CRITERIA_ADDITIONAL_CONDITION_UNK_217 = 217, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_218 = 218, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_219 = 219, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_220 = 220, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_221 = 221, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_222 = 222, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_223 = 223, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_224 = 224, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_225 = 225, // NYI - CRITERIA_ADDITIONAL_CONDITION_USED_LEVEL_BOOST = 226, // NYI - CRITERIA_ADDITIONAL_CONDITION_USED_RACE_CHANGE = 227, // NYI - CRITERIA_ADDITIONAL_CONDITION_USED_FACTION_CHANGE = 228, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_229 = 229, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_230 = 230, // NYI - CRITERIA_ADDITIONAL_CONDITION_ACHIEVEMENT_GLOBALLY_INCOMPLETED = 231, // hall of fame stuff, asset: unk, secondaryAsset: achievementId - CRITERIA_ADDITIONAL_CONDITION_MAIN_HAND_VISIBLE_SUBCLASS = 232, - CRITERIA_ADDITIONAL_CONDITION_OFF_HAND_VISIBLE_SUBCLASS = 233, - CRITERIA_ADDITIONAL_CONDITION_PVP_TIER = 234, // NYI asset: pvpTierId - CRITERIA_ADDITIONAL_CONDITION_AZERITE_ITEM_LEVEL = 235, - //CRITERIA_ADDITIONAL_CONDITION_UNK_236 = 236, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_237 = 237, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_238 = 238, // NYI - CRITERIA_ADDITIONAL_CONDITION_PVP_TIER_GREATER = 239, // NYI asset: pvpTierEnum, secondaryAsset: pvpBracket - //CRITERIA_ADDITIONAL_CONDITION_UNK_240 = 240, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_241 = 241, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_242 = 242, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_243 = 243, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_244 = 244, // NYI - CRITERIA_ADDITIONAL_CONDITION_IN_WAR_MODE = 245, - //CRITERIA_ADDITIONAL_CONDITION_UNK_246 = 246, // NYI - CRITERIA_ADDITIONAL_CONDITION_KEYSTONE_LEVEL = 247, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_248 = 248, // NYI - CRITERIA_ADDITIONAL_CONDITION_KEYSTONE_DUNGEON = 249, // NYI asset: mapChallengeModeId - //CRITERIA_ADDITIONAL_CONDITION_UNK_250 = 250, // NYI - CRITERIA_ADDITIONAL_CONDITION_PVP_SEASON = 251, // NYI asset: that unknown column in PvpSeason.db2 - CRITERIA_ADDITIONAL_CONDITION_SOURCE_DISPLAY_RACE = 252, - CRITERIA_ADDITIONAL_CONDITION_TARGET_DISPLAY_RACE = 253, - CRITERIA_ADDITIONAL_CONDITION_FRIENDSHIP_REP_REACTION_EXACT = 254, // NYI - CRITERIA_ADDITIONAL_CONDITION_SOURCE_AURA_COUNT_EQUAL = 255, - CRITERIA_ADDITIONAL_CONDITION_TARGET_AURA_COUNT_EQUAL = 256, - CRITERIA_ADDITIONAL_CONDITION_SOURCE_AURA_COUNT_GREATER = 257, - CRITERIA_ADDITIONAL_CONDITION_TARGET_AURA_COUNT_GREATER = 258, - CRITERIA_ADDITIONAL_CONDITION_UNLOCKED_AZERITE_ESSENCE_RANK_LOWER = 259, - CRITERIA_ADDITIONAL_CONDITION_UNLOCKED_AZERITE_ESSENCE_RANK_EQUAL = 260, - CRITERIA_ADDITIONAL_CONDITION_UNLOCKED_AZERITE_ESSENCE_RANK_GREATER = 261, - CRITERIA_ADDITIONAL_CONDITION_SOURCE_HAS_AURA_EFFECT_INDEX = 262, // asset: spellId, secondaryAsset: index - CRITERIA_ADDITIONAL_CONDITION_SOURCE_SPECIALIZATION_ROLE = 263, - CRITERIA_ADDITIONAL_CONDITION_SOURCE_LEVEL_120 = 264, - //CRITERIA_ADDITIONAL_CONDITION_UNK_265 = 265, - CRITERIA_ADDITIONAL_CONDITION_SELECTED_AZERITE_ESSENCE_RANK_LOWER = 266, - CRITERIA_ADDITIONAL_CONDITION_SELECTED_AZERITE_ESSENCE_RANK_GREATER = 267, - CRITERIA_ADDITIONAL_CONDITION_SOURCE_LEVEL_IN_RANGE_CT = 268, - CRITERIA_ADDITIONAL_CONDITION_TARGET_LEVEL_IN_RANGE_CT = 269, - //CRITERIA_ADDITIONAL_CONDITION_UNK_270 = 270, - //CRITERIA_ADDITIONAL_CONDITION_UNK_271 = 271, - CRITERIA_ADDITIONAL_CONDITION_SOURCE_LEVEL_GREATER_CT = 272, // compare levels using content tuning - CRITERIA_ADDITIONAL_CONDITION_TARGET_LEVEL_GREATER_CT = 273, // compare levels using content tuning - //CRITERIA_ADDITIONAL_CONDITION_UNK_274 = 274, - //CRITERIA_ADDITIONAL_CONDITION_UNK_275 = 275, - //CRITERIA_ADDITIONAL_CONDITION_UNK_276 = 276, - CRITERIA_ADDITIONAL_CONDITION_RAF_RECRUIT_IN_PARTY = 277, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_278 = 278, - //CRITERIA_ADDITIONAL_CONDITION_UNK_279 = 279, - CRITERIA_ADDITIONAL_CONDITION_MAP_OR_COSMETIC_MAP = 280, - //CRITERIA_ADDITIONAL_CONDITION_UNK_281 = 281, - CRITERIA_ADDITIONAL_CONDITION_HAS_ENTITLEMENT = 282, // NYI - CRITERIA_ADDITIONAL_CONDITION_HAS_QUEST_SESSION = 283, // NYI - //CRITERIA_ADDITIONAL_CONDITION_UNK_284 = 284, - //CRITERIA_ADDITIONAL_CONDITION_UNK_285 = 285, - //CRITERIA_ADDITIONAL_CONDITION_UNK_286 = 286, - //CRITERIA_ADDITIONAL_CONDITION_UNK_287 = 287, - CRITERIA_ADDITIONAL_CONDITION_COVENANT = 288, - //CRITERIA_ADDITIONAL_CONDITION_UNK_289 = 289, // related to pvp ranking - CRITERIA_ADDITIONAL_CONDITION_PERMANENT_ANIMA_DIVERSION_TALENT = 290, // NYI - CRITERIA_ADDITIONAL_CONDITION_SOULBIND = 291, - //CRITERIA_ADDITIONAL_CONDITION_UNK_292 = 292, - CRITERIA_ADDITIONAL_CONDITION_SOURCE_AREA_OR_ZONE_IN_GROUP = 293, - //CRITERIA_ADDITIONAL_CONDITION_UNK_294 = 294, - //CRITERIA_ADDITIONAL_CONDITION_UNK_295 = 295, - //CRITERIA_ADDITIONAL_CONDITION_UNK_296 = 296, - //CRITERIA_ADDITIONAL_CONDITION_UNK_297 = 297, - //CRITERIA_ADDITIONAL_CONDITION_UNK_298 = 298, - //CRITERIA_ADDITIONAL_CONDITION_UNK_299 = 299, - CRITERIA_ADDITIONAL_CONDITION_SOURCE_IN_SPECIFIC_CHROMIE_TIME = 300, - CRITERIA_ADDITIONAL_CONDITION_SOURCE_IN_ANY_CHROMIE_TIME = 301, - //CRITERIA_ADDITIONAL_CONDITION_UNK_302 = 302, - CRITERIA_ADDITIONAL_CONDITION_SOURCE_RUNEFORGE_LEGENDARY_KNOWN = 303, - //CRITERIA_ADDITIONAL_CONDITION_UNK_304 = 304, - //CRITERIA_ADDITIONAL_CONDITION_UNK_305 = 305, - //CRITERIA_ADDITIONAL_CONDITION_UNK_306 = 306, - CRITERIA_ADDITIONAL_CONDITION_SOULBIND_CONDUIT_RANK = 307, // NYI - CRITERIA_ADDITIONAL_CONDITION_SHAPESHIFT_FORM_CUSTOMIZATION_DISPLAY = 308, - CRITERIA_ADDITIONAL_CONDITION_SOULBIND_MIN_CONDUITS_AT_RANK = 309, // NYI - CRITERIA_ADDITIONAL_CONDITION_IS_RESTRICTED_ACCOUNT = 310, // NYI - CRITERIA_ADDITIONAL_CONDITION_SOURCE_FLYING = 311, -}; - enum class CriteriaFailEvent : uint8 { None = 0, @@ -1287,6 +974,333 @@ enum MapDifficultyFlags : uint8 MAP_DIFFICULTY_FLAG_CANNOT_EXTEND = 0x10 }; +enum class ModifierTreeType : int32 +{ + None = 0, // No modifier + PlayerInebriationLevelEqualOrGreaterThan = 1, // Player inebriation level is {#Drunkenness} or more + PlayerMeetsCondition = 2, // Player meets condition "{PlayerCondition}" + MinimumItemLevel = 3, // Minimum item level is {#Item Level} + TargetCreatureId = 4, // Target is NPC "{Creature}" + TargetIsPlayer = 5, // Target is player + TargetIsDead = 6, // Target is dead + TargetIsOppositeFaction = 7, // Target is opposite faction + PlayerHasAura = 8, // Player has aura "{Spell}" + PlayerHasAuraEffect = 9, // Player has aura effect "{SpellAuraNames.EnumID}" + TargetHasAura = 10, // Target has aura "{Spell}" + TargetHasAuraEffect = 11, // Target has aura effect "{SpellAuraNames.EnumID}" + TargetHasAuraState = 12, // Target has aura state "{$Aura State}" + PlayerHasAuraState = 13, // Player has aura state "{$Aura State}" + ItemQualityIsAtLeast = 14, // Item quality is at least {$Item Quality} + ItemQualityIsExactly = 15, // Item quality is exactly {$Item Quality} + PlayerIsAlive = 16, // Player is alive + PlayerIsInArea = 17, // Player is in area "{AreaTable}" + TargetIsInArea = 18, // Target is in area "{AreaTable}" + ItemId = 19, // Item is "{Item}" + LegacyDungeonDifficulty = 20, // Legacy dungeon difficulty is "{$Dungeon Difficulty}" + PlayerToTargetLevelDeltaGreaterThan = 21, // Exceeds the target's level by {#Level Delta} levels + TargetToPlayerLevelDeltaGreaterThan = 22, // Target exceeds your level by {#Level Delta} levels + PlayerLevelEqualTargetLevel = 23, // You and the target are equal level + PlayerInArenaWithTeamSize = 24, // Player is in an arena with team size {#Team Size} + PlayerRace = 25, // Player race is "{ChrRaces}" + PlayerClass = 26, // Player class is "{ChrClasses}" + TargetRace = 27, // Target race is "{ChrRaces}" + TargetClass = 28, // Target class is "{ChrClasses}" + LessThanTappers = 29, // Less than {#Tappers} tappers + CreatureType = 30, // Creature is type "{CreatureType}" + CreatureFamily = 31, // Creature is family "{CreatureFamily}" + PlayerMap = 32, // Player is on map "{Map}" + ClientVersionEqualOrLessThan = 33, // Milestone is at or before "{WowStaticSchemas}" + BattlePetTeamLevel = 34, // All three winning battle pets are at or above level {#Battle Pet Level} + PlayerIsNotInParty = 35, // Player is not in a party + PlayerIsInParty = 36, // Player is in a party + HasPersonalRatingEqualOrGreaterThan = 37, // Has a Personal Rating of at least {#Personal Rating} + HasTitle = 38, // Has title "{CharTitles.Mask_ID}" + PlayerLevelEqual = 39, // Player is exactly level {#Level} + TargetLevelEqual = 40, // Target is exactly level {#Level} + PlayerIsInZone = 41, // Player is in top-level area "{AreaTable}" + TargetIsInZone = 42, // Target is in top-level area "{AreaTable}" + PlayerHealthBelowPercent = 43, // Player health below {#Percent}% + PlayerHealthAbovePercent = 44, // Player health above {#Percent}% + PlayerHealthEqualsPercent = 45, // Player health equals {#Percent}% + TargetHealthBelowPercent = 46, // Target health below {#Percent}% + TargetHealthAbovePercent = 47, // Target health above {#Percent}% + TargetHealthEqualsPercent = 48, // Target health equals {#Percent}% + PlayerHealthBelowValue = 49, // Player health below {#Hit Points} HP + PlayerHealthAboveValue = 50, // Player health above {#Hit Points} HP + PlayerHealthEqualsValue = 51, // Player health equals {#Hit Points} HP + TargetHealthBelowValue = 52, // Target health below {#Hit Points} HP + TargetHealthAboveValue = 53, // Target health above {#Hit Points} HP + TargetHealthEqualsValue = 54, // Target health equals {#Hit Points} HP + TargetIsPlayerAndMeetsCondition = 55, // Target is a player with condition "{PlayerCondition}" + PlayerHasMoreThanAchievementPoints = 56, // Player has over {#Achievement Pts} achievement points + PlayerInLfgDungeon = 57, // Player is in a LFG dungeon + PlayerInRandomLfgDungeon = 58, // Player is in a random LFG dungeon + PlayerInFirstRandomLfgDungeon = 59, // Player is in a first random LFG dungeon + PlayerInRankedArenaMatch = 60, // Player is in a ranked arena match + PlayerInGuildParty = 61, /*NYI*/ // Player is in a guild party + PlayerGuildReputationEqualOrGreaterThan = 62, // Player has guild reputation of {#Guild Reputation} or more + PlayerInRatedBattleground = 63, // Player is in rated battleground + PlayerBattlegroundRatingEqualOrGreaterThan = 64, // Player has a battleground rating of {#Battleground Rating} or more + ResearchProjectRarity = 65, /*NYI*/ // Research project rarity is "{$Project Rarity}" + ResearchProjectBranch = 66, /*NYI*/ // Research project is in branch "{ResearchBranch}" + WorldStateExpression = 67, // World state expression "{WorldStateExpression}" is true + DungeonDifficulty = 68, // Dungeon difficulty is "{Difficulty}" + PlayerLevelEqualOrGreaterThan = 69, // Player level is {#Level} or more + TargetLevelEqualOrGreaterThan = 70, // Target level is {#Level} or more + PlayerLevelEqualOrLessThan = 71, // Player level is {#Level} or less + TargetLevelEqualOrLessThan = 72, // Target level is {#Level} or less + ModifierTree = 73, // Modifier tree "{ModifierTree}" is also true + PlayerScenario = 74, // Player is on scenario "{Scenario}" + TillersReputationGreaterThan = 75, // Reputation with Tillers is above {#Reputation} + BattlePetAchievementPointsEqualOrGreaterThan = 76, // Battle pet achievement points are at least {#Achievement Pts} + UniqueBattlePetsEqualOrGreaterThan = 77, // (Account) At least {#Pets Known} unique pets known + BattlePetType = 78, // Battlepet is of type "{$Battle Pet Types}" + BattlePetHealthPercentLessThan = 79, /*NYI*/ // (Account) Battlepet's health is below {#Health Percent} percent + GuildGroupMemberCountEqualOrGreaterThan = 80, // Be in a group with at least {#Members} guild members + BattlePetOpponentCreatureId = 81, /*NYI*/ // Battle pet opponent is "{Creature}" + PlayerScenarioStep = 82, // Player is on scenario step number {#Step Number} + ChallengeModeMedal = 83, // Challenge mode medal earned is "{#Challenge Mode Medal(OBSOLETE)}" (OBSOLETE) + PlayerOnQuest = 84, // Player is currently on the quest "{QuestV2}" + ExaltedWithFaction = 85, // Reach exalted with "{Faction}" + EarnedAchievementOnAccount = 86, // Earned achievement "{Achievement}" on this account + EarnedAchievementOnPlayer = 87, // Earned achievement "{Achievement}" on this player + OrderOfTheCloudSerpentReputationGreaterThan = 88, // Reputation with Order of the Cloud Serpent is above {#Reputation} + BattlePetQuality = 89, /*NYI*/ // Battle pet is of quality "{BattlePetBreedQuality}" + BattlePetFightWasPVP = 90, /*NYI*/ // Battle pet fight was PVP + BattlePetSpecies = 91, // Battle pet is species type "{BattlePetSpecies}" + ServerExpansionEqualOrGreaterThan = 92, // Server expansion level is "{$Expansion Level}" or higher + PlayerHasBattlePetJournalLock = 93, // Player has battle pet journal lock + FriendshipRepReactionIsMet = 94, // Friendship rep reaction "{FriendshipRepReaction}" is met + ReputationWithFactionIsEqualOrGreaterThan = 95, // Reputation with "{Faction}" is {#Reputation} or more + ItemClassAndSubclass = 96, // Item is class "{ItemClass.ClassID}", subclass "{^ItemSubclass.SubclassID:ItemSubclass.ClassID = ?}" + PlayerGender = 97, // Player's gender is "{$Gender}" + PlayerNativeGender = 98, // Player's native gender is "{$Gender}" + PlayerSkillEqualOrGreaterThan = 99, // Player skill "{SkillLine}" is level {#Skill Level} or higher + PlayerLanguageSkillEqualOrGreaterThan = 100, // Player language "{Languages}" is level {#Language Level} or higher + PlayerIsInNormalPhase = 101, // Player is in normal phase + PlayerIsInPhase = 102, // Player is in phase "{Phase}" + PlayerIsInPhaseGroup = 103, // Player is in phase group "{PhaseGroup}" + PlayerKnowsSpell = 104, // Player knows spell "{Spell}" + PlayerHasItemQuantity = 105, // Player is carrying item "{Item}", quantity {#Quantity} + PlayerExpansionLevelEqualOrGreaterThan = 106, // Player expansion level is "{$Expansion Level}" or higher + PlayerHasAuraWithLabel = 107, // Player has aura with label {Label} + PlayersRealmWorldState = 108, // Player's realm state "{WorldState}" equals {#Value} + TimeBetween = 109, // Time is between "{/Begin Date}" and "{/End Date}" + PlayerHasCompletedQuest = 110, // Player has previously completed quest "{QuestV2}" + PlayerIsReadyToTurnInQuest = 111, // Player is ready to turn in quest "{QuestV2}" + PlayerHasCompletedQuestObjective = 112, // Player has completed Quest Objective "{QuestObjective}" + PlayerHasExploredArea = 113, // Player has explored area "{AreaTable}" + PlayerHasItemQuantityIncludingBank = 114, // Player or bank has item "{Item}", quantity {#Quantity} + Weather = 115, // Weather is "{Weather}" + PlayerFaction = 116, // Player faction is {$Player Faction} + LfgStatusEqual = 117, // Looking-for-group status "{$LFG Status}" equals {#Value} + LFgStatusEqualOrGreaterThan = 118, // Looking-for-group status "{$LFG Status}" is {#Value} or more + PlayerHasCurrencyEqualOrGreaterThan = 119, // Player has currency "{CurrencyTypes}" in amount {#Amount} or more + TargetThreatListSizeLessThan = 120, // Player Killed creature with less than "{#Targets}" threat list targets + PlayerHasTrackedCurrencyEqualOrGreaterThan = 121, // Player has currency "{CurrencyTypes}" tracked (per season) in amount {#Amount} or more + PlayerMapInstanceType = 122, // Player is on a map of type "{@INSTANCE_TYPE}" + PlayerInTimeWalkerInstance = 123, // Player was in a Time Walker instance + PvpSeasonIsActive = 124, // PVP season is active + PvpSeason = 125, // Current PVP season is {#Season} + GarrisonTierEqualOrGreaterThan = 126, // Garrison is tier {#Tier} or higher for garrison type "{GarrType}" + GarrisonFollowersWithLevelEqualOrGreaterThan = 127, // At least {#Followers} followers of at least level {#Level} for follower type "{GarrFollowerType}" + GarrisonFollowersWithQualityEqualOrGreaterThan = 128, // At least {#Followers} followers at least quality "{@GARR_FOLLOWER_QUALITY}" for follower type "{GarrFollowerType}" + GarrisonFollowerWithAbilityAtLevelEqualOrGreaterThan = 129, // Follower of at least level {#Level} has ability {GarrAbility} for follower type "{GarrFollowerType}" + GarrisonFollowerWithTraitAtLevelEqualOrGreaterThan = 130, // Follower of at least level {#Level} has trait {GarrAbility} for follower type "{GarrFollowerType}" + GarrisonFollowerWithAbilityAssignedToBuilding = 131, // Follower with ability "{GarrAbility}" is assigned to building type "{@GARRISON_BUILDING_TYPE}" for garrison type "{GarrType}" + GarrisonFollowerWithTraitAssignedToBuilding = 132, // Follower with trait "{GarrAbility}" is assigned to building type "{@GARRISON_BUILDING_TYPE}" for garrison type "{GarrType}" + GarrisonFollowerWithLevelAssignedToBuilding = 133, // Follower at least level {#Level} is assigned to building type "{@GARRISON_BUILDING_TYPE}" for garrison type "GarrType}" + GarrisonBuildingWithLevelEqualOrGreaterThan = 134, // Building "{@GARRISON_BUILDING_TYPE}" is at least level {#Level} for garrison type "{GarrType}" + HasBlueprintForGarrisonBuilding = 135, // Has blueprint for garrison building "{GarrBuilding}" of type "{GarrType}" + HasGarrisonBuildingSpecialization = 136, // Has garrison building specialization "{GarrSpecialization}" + AllGarrisonPlotsAreFull = 137, // All garrison type "{GarrType}" plots are full + PlayerIsInOwnGarrison = 138, // Player is in their own garrison + GarrisonShipmentOfTypeIsPending = 139, /*NYI*/ // Shipment of type "{CharShipmentContainer}" is pending + GarrisonBuildingIsUnderConstruction = 140, // Garrison building "{GarrBuilding}" is under construction + GarrisonMissionHasBeenCompleted = 141, /*NYI*/ // Garrison mission "{GarrMission}" has been completed + GarrisonBuildingLevelEqual = 142, // Building {@GARRISON_BUILDING_TYPE} is exactly level {#Level} for garrison type "{GarrType}" + GarrisonFollowerHasAbility = 143, // This follower has ability "{GarrAbility}" for garrison type "{GarrType}" + GarrisonFollowerHasTrait = 144, // This follower has trait "{GarrAbility}" for garrison type "{GarrType}" + GarrisonFollowerQualityEqual = 145, // This Garrison Follower is {@GARR_FOLLOWER_QUALITY} quality + GarrisonFollowerLevelEqual = 146, // This Garrison Follower is level {#Level} + GarrisonMissionIsRare = 147, /*NYI*/ // This Garrison Mission is Rare + GarrisonMissionIsElite = 148, /*NYI*/ // This Garrison Mission is Elite + CurrentGarrisonBuildingLevelEqual = 149, // This Garrison Building is level {#Level} - building type passed as argument + GarrisonPlotInstanceHasBuildingThatIsReadyToActivate = 150, // Garrison plot instance "{GarrPlotInstance}" has building that is ready to activate + BattlePetTeamWithSpeciesEqualOrGreaterThan = 151, // Battlepet: with at least {#Amount} "{BattlePetSpecies}" + BattlePetTeamWithTypeEqualOrGreaterThan = 152, // Battlepet: with at least {#Amount} pets of type "{$Battle Pet Types}" + PetBattleLastAbility = 153, /*NYI*/ // Battlepet: last ability was "{BattlePetAbility}" + PetBattleLastAbilityType = 154, /*NYI*/ // Battlepet: last ability was of type "{$Battle Pet Types}" + BattlePetTeamWithAliveEqualOrGreaterThan = 155, // Battlepet: with at least {#Alive} alive + HasGarrisonBuildingActiveSpecialization = 156, // Has Garrison building active specialization "{GarrSpecialization}" + HasGarrisonFollower = 157, // Has Garrison follower "{GarrFollower}" + PlayerQuestObjectiveProgressEqual = 158, // Player's progress on Quest Objective "{QuestObjective}" is equal to {#Value} + PlayerQuestObjectiveProgressEqualOrGreaterThan = 159, // Player's progress on Quest Objective "{QuestObjective}" is at least {#Value} + IsPTRRealm = 160, // This is a PTR Realm + IsBetaRealm = 161, // This is a Beta Realm + IsQARealm = 162, // This is a QA Realm + GarrisonShipmentContainerIsFull = 163, /*NYI*/ // Shipment Container "{CharShipmentContainer}" is full + PlayerCountIsValidToStartGarrisonInvasion = 164, // Player count is valid to start garrison invasion + InstancePlayerCountEqualOrLessThan = 165, // Instance has at most {#Players} players + AllGarrisonPlotsFilledWithBuildingsWithLevelEqualOrGreater = 166, // All plots are full and at least level {#Level} for garrison type "{GarrType}" + GarrisonMissionType = 167, /*NYI*/ // This mission is type "{GarrMissionType}" + GarrisonFollowerItemLevelEqualOrGreaterThan = 168, // This follower is at least item level {#Level} + GarrisonFollowerCountWithItemLevelEqualOrGreaterThan = 169, // At least {#Followers} followers are at least item level {#Level} for follower type "{GarrFollowerType}" + GarrisonTierEqual = 170, // Garrison is exactly tier {#Tier} for garrison type "{GarrType}" + InstancePlayerCountEqual = 171, // Instance has exactly {#Players} players + CurrencyId = 172, // The currency is type "{CurrencyTypes}" + SelectionIsPlayerCorpse = 173, // Target is player corpse + PlayerCanAcceptQuest = 174, // Player is currently eligible for quest "{QuestV2}" + GarrisonFollowerCountWithLevelEqualOrGreaterThan = 175, // At least {#Followers} followers exactly level {#Level} for follower type "{GarrFollowerType}" + GarrisonFollowerIsInBuilding = 176, // Garrison follower "{GarrFollower}" is in building "{GarrBuilding}" + GarrisonMissionCountLessThan = 177, /*NYI*/ // Player has less than {#Available} available and {#In-Progress} in-progress missions of garrison type "{GarrType}" + GarrisonPlotInstanceCountEqualOrGreaterThan = 178, // Player has at least {#Amount} instances of plot "{GarrPlot}" available + CurrencySource = 179, /*NYI*/ // Currency source is {$Currency Source} + PlayerIsInNotOwnGarrison = 180, // Player is in another garrison (not their own) + HasActiveGarrisonFollower = 181, // Has active Garrison follower "{GarrFollower}" + PlayerDailyRandomValueMod_X_Equals = 182, /*NYI*/ // Player daily random value mod {#Mod Value} equals {#Equals Value} + PlayerHasMount = 183, // Player has Mount "{Mount}" + GarrisonFollowerCountWithInactiveWithItemLevelEqualOrGreaterThan = 184, // At least {#Followers} followers (including inactive) are at least item level {#Level} for follower type "{GarrFollowerType}" + GarrisonFollowerIsOnAMission = 185, // Garrison follower "{GarrFollower}" is on a mission + GarrisonMissionCountInSetLessThan = 186, /*NYI*/ // Player has less than {#Missions} available and in-progress missions of set "{GarrMissionSet}" in garrison type "{GarrType}" + GarrisonFollowerType = 187, // This Garrison Follower is of type "{GarrFollowerType}" + PlayerUsedBoostLessThanHoursAgoRealTime = 188, /*NYI*/ // Player has boosted and boost occurred < {#Hours} hours ago (real time) + PlayerUsedBoostLessThanHoursAgoGameTime = 189, /*NYI*/ // Player has boosted and boost occurred < {#Hours} hours ago (in-game time) + PlayerIsMercenary = 190, // Player is currently Mercenary + PlayerEffectiveRace = 191, /*NYI*/ // Player effective race is "{ChrRaces}" + TargetEffectiveRace = 192, /*NYI*/ // Target effective race is "{ChrRaces}" + HonorLevelEqualOrGreaterThan = 193, // Honor level >= {#Level} + PrestigeLevelEqualOrGreaterThan = 194, // Prestige level >= {#Level} + GarrisonMissionIsReadyToCollect = 195, /*NYI*/ // Garrison mission "{GarrMission}" is ready to collect + PlayerIsInstanceOwner = 196, /*NYI*/ // Player is the instance owner (requires 'Lock Instance Owner' LFGDungeon flag) + PlayerHasHeirloom = 197, // Player has heirloom "{Item}" + TeamPoints = 198, /*NYI*/ // Team has {#Points} Points + PlayerHasToy = 199, // Player has toy "{Item}" + PlayerHasTransmog = 200, // Player has transmog "{ItemModifiedAppearance}" + GarrisonTalentSelected = 201, /*NYI*/ // Garrison has talent "{GarrTalent}" selected + GarrisonTalentResearched = 202, /*NYI*/ // Garrison has talent "{GarrTalent}" researched + PlayerHasRestriction = 203, // Player has restriction of type "{@CHARACTER_RESTRICTION_TYPE}" + PlayerCreatedCharacterLessThanHoursAgoRealTime = 204, /*NYI*/ // Player has created their character < {#Hours} hours ago (real time) + PlayerCreatedCharacterLessThanHoursAgoGameTime = 205, // Player has created their character < {#Hours} hours ago (in-game time) + QuestHasQuestInfoId = 206, // Quest has Quest Info "{QuestInfo}" + GarrisonTalentResearchInProgress = 207, /*NYI*/ // Garrison is researching talent "{GarrTalent}" + PlayerEquippedArtifactAppearanceSet = 208, // Player has equipped Artifact Appearance Set "{ArtifactAppearanceSet}" + PlayerHasCurrencyEqual = 209, // Player has currency "{CurrencyTypes}" in amount {#Amount} exactly + MinimumAverageItemHighWaterMarkForSpec = 210, /*NYI*/ // Minimum average item high water mark is {#Item High Water Mark} for "{$Item History Spec Match}") + PlayerScenarioType = 211, // Player in scenario of type "{$Scenario Type}" + PlayersAuthExpansionLevelEqualOrGreaterThan = 212, // Player's auth expansion level is "{$Expansion Level}" or higher + PlayerLastWeek2v2Rating = 213, /*NYI*/ // Player achieved at least a rating of {#Rating} in 2v2 last week player played + PlayerLastWeek3v3Rating = 214, /*NYI*/ // Player achieved at least a rating of {#Rating} in 3v3 last week player played + PlayerLastWeekRBGRating = 215, /*NYI*/ // Player achieved at least a rating of {#Rating} in RBG last week player played + GroupMemberCountFromConnectedRealmEqualOrGreaterThan = 216, // At least {#Num Players} members of the group are from your connected realms + ArtifactTraitUnlockedCountEqualOrGreaterThan = 217, // At least {#Num Traits} traits have been unlocked in artifact "{Item}" + ParagonReputationLevelEqualOrGreaterThan = 218, // Paragon level >= "{#Level}" + GarrisonShipmentIsReady = 219, /*NYI*/ // Shipment in container type "{CharShipmentContainer}" ready + PlayerIsInPvpBrawl = 220, // Player is in PvP Brawl + ParagonReputationLevelWithFactionEqualOrGreaterThan = 221, // Paragon level >= "{#Level}" with faction "{Faction}" + PlayerHasItemWithBonusListFromTreeAndQuality = 222, // Player has an item with bonus list from tree "{ItemBonusTree}" and of quality "{$Item Quality}" + PlayerHasEmptyInventorySlotCountEqualOrGreaterThan = 223, // Player has at least "{#Number of empty slots}" empty inventory slots + PlayerHasItemInHistoryOfProgressiveEvent = 224, /*NYI*/ // Player has item "{Item}" in the item history of progressive event "{ProgressiveEvent}" + PlayerHasArtifactPowerRankCountPurchasedEqualOrGreaterThan = 225, // Player has at least {#Purchased Ranks} ranks of {ArtifactPower} on equipped artifact + PlayerHasBoosted = 226, // Player has boosted + PlayerHasRaceChanged = 227, // Player has race changed + PlayerHasBeenGrantedLevelsFromRaF = 228, // Player has been granted levels from Recruit a Friend + IsTournamentRealm = 229, // Is Tournament Realm + PlayerCanAccessAlliedRaces = 230, // Player can access allied races + GroupMemberCountWithAchievementEqualOrLessThan = 231, // No More Than {#Group Members} With Achievement {Achievement} In Group (true if no group) + PlayerMainhandWeaponType = 232, // Player has main hand weapon of type "{$Weapon Type}" + PlayerOffhandWeaponType = 233, // Player has off-hand weapon of type "{$Weapon Type}" + PlayerPvpTier = 234, // Player is in PvP tier {PvpTier} + PlayerAzeriteLevelEqualOrGreaterThan = 235, // Players' Azerite Item is at or above level "{#Azerite Level}" + PlayerIsOnQuestInQuestline = 236, // Player is on quest in questline "{QuestLine}" + PlayerIsQnQuestLinkedToScheduledWorldStateGroup = 237, // Player is on quest associated with current progressive unlock group "{ScheduledWorldStateGroup}" + PlayerIsInRaidGroup = 238, // Player is in raid group + PlayerPvpTierInBracketEqualOrGreaterThan = 239, // Player is at or above "{@PVP_TIER_ENUM}" for "{@PVP_BRACKET}" + PlayerCanAcceptQuestInQuestline = 240, // Player is eligible for quest in questline "{Questline}" + PlayerHasCompletedQuestline = 241, // Player has completed questline "{Questline}" + PlayerHasCompletedQuestlineQuestCount = 242, // Player has completed "{#Quests}" quests in questline "{Questline}" + PlayerHasCompletedPercentageOfQuestline = 243, // Player has completed "{#Percentage}" % of quests in questline "{Questline}" + PlayerHasWarModeEnabled = 244, // Player has WarMode Enabled (regardless of shard state) + PlayerIsOnWarModeShard = 245, // Player is on a WarMode Shard + PlayerIsAllowedToToggleWarModeInArea = 246, // Player is allowed to toggle WarMode in area + MythicPlusKeystoneLevelEqualOrGreaterThan = 247, /*NYI*/ // Mythic Plus Keystone Level Atleast {#Level} + MythicPlusCompletedInTime = 248, /*NYI*/ // Mythic Plus Completed In Time + MythicPlusMapChallengeMode = 249, /*NYI*/ // Mythic Plus Map Challenge Mode {MapChallengeMode} + MythicPlusDisplaySeason = 250, /*NYI*/ // Mythic Plus Display Season {#Season} + MythicPlusMilestoneSeason = 251, /*NYI*/ // Mythic Plus Milestone Season {#Season} + PlayerVisibleRace = 252, // Player visible race is "{ChrRaces}" + TargetVisibleRace = 253, // Target visible race is "{ChrRaces}" + FriendshipRepReactionEqual = 254, // Friendship rep reaction is exactly "{FriendshipRepReaction}" + PlayerAuraStackCountEqual = 255, // Player has exactly {#Stacks} stacks of aura "{Spell}" + TargetAuraStackCountEqual = 256, // Target has exactly {#Stacks} stacks of aura "{Spell}" + PlayerAuraStackCountEqualOrGreaterThan = 257, // Player has at least {#Stacks} stacks of aura "{Spell}" + TargetAuraStackCountEqualOrGreaterThan = 258, // Target has at least {#Stacks} stacks of aura "{Spell}" + PlayerHasAzeriteEssenceRankLessThan = 259, // Player has Azerite Essence {AzeriteEssence} at less than rank {#rank} + PlayerHasAzeriteEssenceRankEqual = 260, // Player has Azerite Essence {AzeriteEssence} at rank {#rank} + PlayerHasAzeriteEssenceRankGreaterThan = 261, // Player has Azerite Essence {AzeriteEssence} at greater than rank {#rank} + PlayerHasAuraWithEffectIndex = 262, // Player has Aura {Spell} with Effect Index {#index} active + PlayerLootSpecializationMatchesRole = 263, // Player loot specialization matches role {@LFG_ROLE} + PlayerIsAtMaxExpansionLevel = 264, // Player is at max expansion level + TransmogSource = 265, // Transmog Source is "{@TRANSMOG_SOURCE}" + PlayerHasAzeriteEssenceInSlotAtRankLessThan = 266, // Player has Azerite Essence in slot {@AZERITE_ESSENCE_SLOT} at less than rank {#rank} + PlayerHasAzeriteEssenceInSlotAtRankGreaterThan = 267, // Player has Azerite Essence in slot {@AZERITE_ESSENCE_SLOT} at greater than rank {#rank} + PlayerLevelWithinContentTuning = 268, // Player has level within Content Tuning {ContentTuning} + TargetLevelWithinContentTuning = 269, // Target has level within Content Tuning {ContentTuning} + PlayerIsScenarioInitiator = 270, /*NYI*/ // Player is Scenario Initiator + PlayerHasCompletedQuestOrIsOnQuest = 271, // Player is currently on or previously completed quest "{QuestV2}" + PlayerLevelWithinOrAboveContentTuning = 272, // Player has level within or above Content Tuning {ContentTuning} + TargetLevelWithinOrAboveContentTuning = 273, // Target has level within or above Content Tuning {ContentTuning} + PlayerLevelWithinOrAboveLevelRange = 274, /*NYI*/ // Player has level within or above Level Range {LevelRange} + TargetLevelWithinOrAboveLevelRange = 275, /*NYI*/ // Target has level within or above Level Range {LevelRange} + MaxJailersTowerLevelEqualOrGreaterThan = 276, // Max Jailers Tower Level Atleast {#Level} + GroupedWithRaFRecruit = 277, // Grouped With Recruit + GroupedWithRaFRecruiter = 278, // Grouped with Recruiter + PlayerSpecialization = 279, // Specialization is "{ChrSpecialization}" + PlayerMapOrCosmeticChildMap = 280, // Player is on map or cosmetic child map "{Map}" + PlayerCanAccessShadowlandsPrepurchaseContent = 281, // Player can access Shadowlands (9.0) prepurchase content + PlayerHasEntitlement = 282, /*NYI*/ // Player has entitlement "{BattlePayDeliverable}" + PlayerIsInPartySyncGroup = 283, /*NYI*/ // Player is in party sync group + QuestHasPartySyncRewards = 284, /*NYI*/ // Quest is eligible for party sync rewards + HonorGainSource = 285, /*NYI*/ // Player gained honor from source {@SPECIAL_MISC_HONOR_GAIN_SOURCE} + JailersTowerActiveFloorIndexEqualOrGreaterThan = 286, /*NYI*/ // Active Floor Index Atleast {#Level} + JailersTowerActiveFloorDifficultyEqualOrGreaterThan = 287, /*NYI*/ // Active Floor Difficulty Atleast {#Level} + PlayerCovenant = 288, // Player is member of covenant "{Covenant}" + HasTimeEventPassed = 289, // Has time event "{TimeEvent}" passed + GarrisonHasPermanentTalent = 290, /*NYI*/ // Garrison has permanent talent "{GarrTalent}" + HasActiveSoulbind = 291, // Has Active Soulbind "{Soulbind}" + HasMemorizedSpell = 292, /*NYI*/ // Has memorized spell "{Spell}" + PlayerHasAPACSubscriptionReward_2020 = 293, // Player has APAC Subscription Reward 2020 + PlayerHasTBCCDEWarpStalker_Mount = 294, // Player has TBCC:DE Warp Stalker Mount + PlayerHasTBCCDEDarkPortal_Toy = 295, // Player has TBCC:DE Dark Portal Toy + PlayerHasTBCCDEPathOfIllidan_Toy = 296, // Player has TBCC:DE Path of Illidan Toy + PlayerHasImpInABallToySubscriptionReward = 297, // Player has Imp in a Ball Toy Subscription Reward + PlayerIsInAreaGroup = 298, // Player is in area group "{AreaGroup}" + TargetIsInAreaGroup = 299, // Target is in area group "{AreaGroup}" + PlayerIsInChromieTime = 300, // Player has selected Chromie Time ID "{UiChromieTimeExpansionInfo}" + PlayerIsInAnyChromieTime = 301, // Player has selected ANY Chromie Time ID + ItemIsAzeriteArmor = 302, // Item is Azerite Armor + PlayerHasRuneforgePower = 303, // Player Has Runeforge Power "{RuneforgeLegendaryAbility}" + PlayerInChromieTimeForScaling = 304, // Player is Chromie Time for Scaling + IsRaFRecruit = 305, // Is RAF recruit + AllPlayersInGroupHaveAchievement = 306, // All Players In Group Have Achievement "{Achievement}" + PlayerHasSoulbindConduitRankEqualOrGreaterThan = 307, /*NYI*/ // Player has Conduit "{SoulbindConduit}" at Rank {#Rank} or Higher + PlayerSpellShapeshiftFormCreatureDisplayInfoSelection = 308, // Player has chosen {CreatureDisplayInfo} for shapeshift form {SpellShapeshiftForm} + PlayerSoulbindConduitCountAtRankEqualOrGreaterThan = 309, /*NYI*/ // Player has at least {#Level} Conduits at Rank {#Rank} or higher. + PlayerIsRestrictedAccount = 310, // Player is a Restricted Account + PlayerIsFlying = 311, // Player is flying + PlayerScenarioIsLastStep = 312, // Player is on the last step of a Scenario + PlayerHasWeeklyRewardsAvailable = 313, // Player has weekly rewards available + TargetCovenant = 314, // Target is member of covenant "{Covenant}" + PlayerHasTBCCollectorsEdition = 315, // Player has TBC Collector's Edition + PlayerHasWrathCollectorsEdition = 316, // Player has Wrath Collector's Edition + GarrisonTalentResearchedAndAtRankEqualOrGreaterThan = 317, /*NYI*/ // Garrison has talent "{GarrTalent}" researched and active at or above {#Rank} + CurrencySpentOnGarrisonTalentResearchEqualOrGreaterThan = 318, /*NYI*/ // Currency {CurrencyTypes} Spent on Garrison Talent Research in Tree {GarrTalentTree} is greater than or equal to {#Quantity} + RenownCatchupActive = 319, /*NYI*/ // Renown Catchup Active + RapidRenownCatchupActive = 320, /*NYI*/ // Rapid Renown Catchup Active + PlayerMythicPlusRatingEqualOrGreaterThan = 321, /*NYI*/ // Player has Mythic+ Rating of at least "{#DungeonScore}" + PlayerMythicPlusRunCountInCurrentExpansionEqualOrGreaterThan = 322, /*NYI*/ // Player has completed at least "{#MythicKeystoneRuns}" Mythic+ runs in current expansion +}; + enum class ModifierTreeOperator : int8 { SingleTrue = 2, diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index a955c5904ca..3cd6b003daa 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -2468,6 +2468,29 @@ void Item::InitArtifactPowers(uint8 artifactId, uint8 artifactTier) } } +uint32 Item::GetTotalUnlockedArtifactPowers() const +{ + uint32 purchased = GetTotalPurchasedArtifactPowers(); + uint64 artifactXp = m_itemData->ArtifactXP; + uint32 currentArtifactTier = GetModifier(ITEM_MODIFIER_ARTIFACT_TIER); + uint32 extraUnlocked = 0; + do + { + uint64 xpCost = 0; + if (GtArtifactLevelXPEntry const* cost = sArtifactLevelXPGameTable.GetRow(purchased + extraUnlocked + 1)) + xpCost = uint64(currentArtifactTier == MAX_ARTIFACT_TIER ? cost->XP2 : cost->XP); + + if (artifactXp < xpCost) + break; + + artifactXp -= xpCost; + ++extraUnlocked; + + } while (true); + + return purchased + extraUnlocked; +} + uint32 Item::GetTotalPurchasedArtifactPowers() const { uint32 purchasedRanks = 0; diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h index e620e6e5491..d2b3bb702ae 100644 --- a/src/server/game/Entities/Item/Item.h +++ b/src/server/game/Entities/Item/Item.h @@ -411,6 +411,7 @@ class TC_GAME_API Item : public Object void SetArtifactPower(uint16 artifactPowerId, uint8 purchasedRank, uint8 currentRankWithBonus); void InitArtifactPowers(uint8 artifactId, uint8 artifactTier); + uint32 GetTotalUnlockedArtifactPowers() const; uint32 GetTotalPurchasedArtifactPowers() const; void ApplyArtifactPowerEnchantmentBonuses(EnchantmentSlot slot, uint32 enchantId, bool apply, Player* owner); void CopyArtifactDataFromParent(Item* parent); diff --git a/src/server/game/Entities/Player/CollectionMgr.cpp b/src/server/game/Entities/Player/CollectionMgr.cpp index 689965a33d1..bf1ed68072e 100644 --- a/src/server/game/Entities/Player/CollectionMgr.cpp +++ b/src/server/game/Entities/Player/CollectionMgr.cpp @@ -799,7 +799,7 @@ void CollectionMgr::AddItemAppearance(ItemModifiedAppearanceEntry const* itemMod { int32 transmogSlot = ItemTransmogrificationSlots[item->InventoryType]; if (transmogSlot >= 0) - _owner->GetPlayer()->UpdateCriteria(CRITERIA_TYPE_APPEARANCE_UNLOCKED_BY_SLOT, transmogSlot, 1); + _owner->GetPlayer()->UpdateCriteria(CRITERIA_TYPE_APPEARANCE_UNLOCKED_BY_SLOT, transmogSlot, itemModifiedAppearance->ID); } if (std::vector<TransmogSetEntry const*> const* sets = sDB2Manager.GetTransmogSetsForItemModifiedAppearance(itemModifiedAppearance->ID)) diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 89ddc54146c..a99c1af16fc 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -9969,6 +9969,50 @@ uint8 Player::FindEquipSlot(Item const* item, uint32 slot, bool swap) const return NULL_SLOT; } +uint32 Player::GetFreeInventorySlotCount(EnumFlag<ItemSearchLocation> location /*= ItemSearchLocation::Inventory*/) const +{ + uint32 freeSlotCount = 0; + + if (location.HasFlag(ItemSearchLocation::Equipment)) + for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i) + if (!GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + ++freeSlotCount; + + if (location.HasFlag(ItemSearchLocation::Inventory)) + { + uint8 inventoryEnd = INVENTORY_SLOT_ITEM_START + GetInventorySlotCount(); + for (uint8 i = INVENTORY_SLOT_BAG_START; i < inventoryEnd; ++i) + if (!GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + ++freeSlotCount; + + for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i) + if (Bag* bag = GetBagByPos(i)) + for (uint32 j = 0; j < GetBagSize(bag); ++j) + if (!GetItemInBag(bag, j)) + ++freeSlotCount; + } + + if (location.HasFlag(ItemSearchLocation::Bank)) + { + for (uint8 i = BANK_SLOT_ITEM_START; i < BANK_SLOT_BAG_END; ++i) + if (!GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + ++freeSlotCount; + + for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i) + if (Bag* bag = GetBagByPos(i)) + for (uint32 j = 0; j < GetBagSize(bag); ++j) + if (!GetItemInBag(bag, j)) + ++freeSlotCount; + } + + if (location.HasFlag(ItemSearchLocation::ReagentBank)) + for (uint8 i = REAGENT_SLOT_START; i < REAGENT_SLOT_END; ++i) + if (!GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + ++freeSlotCount; + + return freeSlotCount; +} + InventoryResult Player::CanUnequipItems(uint32 item, uint32 count) const { InventoryResult res = EQUIP_ERR_OK; @@ -23226,19 +23270,13 @@ bool Player::BuyItemFromVendorSlot(ObjectGuid vendorguid, uint32 vendorslot, uin uint32 Player::GetMaxPersonalArenaRatingRequirement(uint32 minarenaslot) const { // returns the maximal personal arena rating that can be used to purchase items requiring this condition - // the personal rating of the arena team must match the required limit as well - // so return max[in arenateams](min(personalrating[teamtype], teamrating[teamtype])) + // so return max[in arenateams](personalrating[teamtype]) uint32 max_personal_rating = 0; for (uint8 i = minarenaslot; i < MAX_ARENA_SLOT; ++i) { - if (ArenaTeam* at = sArenaTeamMgr->GetArenaTeamById(GetArenaTeamId(i))) - { - uint32 p_rating = GetArenaPersonalRating(i); - uint32 t_rating = at->GetRating(); - p_rating = p_rating < t_rating ? p_rating : t_rating; - if (max_personal_rating < p_rating) - max_personal_rating = p_rating; - } + uint32 p_rating = GetArenaPersonalRating(i); + if (max_personal_rating < p_rating) + max_personal_rating = p_rating; } return max_personal_rating; } @@ -26514,6 +26552,11 @@ uint32 Player::GetAchievementPoints() const return m_achievementMgr->GetAchievementPoints(); } +std::vector<uint32> Player::GetCompletedAchievementIds() const +{ + return m_achievementMgr->GetCompletedAchievementIds(); +} + bool Player::HasAchieved(uint32 achievementId) const { return m_achievementMgr->HasAchieved(achievementId); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index e9cf9ed7fac..6298598605a 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1260,6 +1260,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void UpdateAverageItemLevelEquipped(); uint8 FindEquipSlot(Item const* item, uint32 slot, bool swap) const; + uint32 GetFreeInventorySlotCount(EnumFlag<ItemSearchLocation> location = ItemSearchLocation::Inventory) const; uint32 GetItemCount(uint32 item, bool inBankAlso = false, Item* skipItem = nullptr) const; uint32 GetItemCountWithLimitCategory(uint32 limitCategory, Item* skipItem = nullptr) const; Item* GetItemByGuid(ObjectGuid guid) const; @@ -2490,6 +2491,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void SendRespondInspectAchievements(Player* player) const; uint32 GetAchievementPoints() const; + std::vector<uint32> GetCompletedAchievementIds() const; bool HasAchieved(uint32 achievementId) const; void ResetAchievements(); void ResetCriteria(CriteriaFailEvent condition, int32 failAsset, bool evenIfCriteriaComplete = false); diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 4bb66052f90..1b8aef79de5 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -431,7 +431,7 @@ void WorldSession::HandleCharEnum(CharacterDatabaseQueryHolder* holder) while (result->NextRow()); } - charEnum.IsAlliedRacesCreationAllowed = GetAccountExpansion() >= EXPANSION_BATTLE_FOR_AZEROTH; + charEnum.IsAlliedRacesCreationAllowed = CanAccessAlliedRaces(); for (std::pair<uint8 const, RaceUnlockRequirement> const& requirement : sObjectMgr->GetRaceUnlockRequirements()) { diff --git a/src/server/game/Scenarios/Scenario.cpp b/src/server/game/Scenarios/Scenario.cpp index b669a59edfd..6e92b5625f4 100644 --- a/src/server/game/Scenarios/Scenario.cpp +++ b/src/server/game/Scenarios/Scenario.cpp @@ -28,8 +28,8 @@ Scenario::Scenario(ScenarioData const* scenarioData) : _data(scenarioData), _cur { ASSERT(_data); - for (auto step : _data->Steps) - SetStepState(step.second, SCENARIO_STEP_NOT_STARTED); + for (std::pair<uint8 const, ScenarioStepEntry const*> const& scenarioStep : _data->Steps) + SetStepState(scenarioStep.second, SCENARIO_STEP_NOT_STARTED); if (ScenarioStepEntry const* step = GetFirstStep()) SetStep(step); @@ -112,12 +112,12 @@ void Scenario::OnPlayerExit(Player* player) bool Scenario::IsComplete() { - for (auto step : _data->Steps) + for (std::pair<uint8 const, ScenarioStepEntry const*> const& scenarioStep : _data->Steps) { - if (step.second->IsBonusObjective()) + if (scenarioStep.second->IsBonusObjective()) continue; - if (GetStepState(step.second) != SCENARIO_STEP_DONE) + if (GetStepState(scenarioStep.second) != SCENARIO_STEP_DONE) return false; } @@ -222,7 +222,7 @@ void Scenario::BuildScenarioState(WorldPackets::Scenario::ScenarioState* scenari scenarioState->CriteriaProgress = GetCriteriasProgress(); scenarioState->BonusObjectives = GetBonusObjectivesData(); // Don't know exactly what this is for, but seems to contain list of scenario steps that we're either on or that are completed - for (auto state : _stepStates) + for (std::pair<ScenarioStepEntry const* const, ScenarioStepState> const& state : _stepStates) { if (state.first->IsBonusObjective()) continue; @@ -246,7 +246,7 @@ ScenarioStepEntry const* Scenario::GetFirstStep() const { // Do it like this because we don't know what order they're in inside the container. ScenarioStepEntry const* firstStep = nullptr; - for (auto scenarioStep : _data->Steps) + for (std::pair<uint8 const, ScenarioStepEntry const*> const& scenarioStep : _data->Steps) { if (scenarioStep.second->IsBonusObjective()) continue; @@ -258,6 +258,22 @@ ScenarioStepEntry const* Scenario::GetFirstStep() const return firstStep; } +ScenarioStepEntry const* Scenario::GetLastStep() const +{ + // Do it like this because we don't know what order they're in inside the container. + ScenarioStepEntry const* lastStep = nullptr; + for (std::pair<uint8 const, ScenarioStepEntry const*> const& scenarioStep : _data->Steps) + { + if (scenarioStep.second->IsBonusObjective()) + continue; + + if (!lastStep || scenarioStep.second->OrderIndex > lastStep->OrderIndex) + lastStep = scenarioStep.second; + } + + return lastStep; +} + void Scenario::SendScenarioState(Player* player) { WorldPackets::Scenario::ScenarioState scenarioState; @@ -268,16 +284,16 @@ void Scenario::SendScenarioState(Player* player) std::vector<WorldPackets::Scenario::BonusObjectiveData> Scenario::GetBonusObjectivesData() { std::vector<WorldPackets::Scenario::BonusObjectiveData> bonusObjectivesData; - for (auto itr = _data->Steps.begin(); itr != _data->Steps.end(); ++itr) + for (std::pair<uint8 const, ScenarioStepEntry const*> const& scenarioStep : _data->Steps) { - if (!itr->second->IsBonusObjective()) + if (!scenarioStep.second->IsBonusObjective()) continue; - if (sCriteriaMgr->GetCriteriaTree(itr->second->Criteriatreeid)) + if (sCriteriaMgr->GetCriteriaTree(scenarioStep.second->Criteriatreeid)) { WorldPackets::Scenario::BonusObjectiveData bonusObjectiveData; - bonusObjectiveData.BonusObjectiveID = itr->second->ID; - bonusObjectiveData.ObjectiveComplete = GetStepState(itr->second) == SCENARIO_STEP_DONE; + bonusObjectiveData.BonusObjectiveID = scenarioStep.second->ID; + bonusObjectiveData.ObjectiveComplete = GetStepState(scenarioStep.second) == SCENARIO_STEP_DONE; bonusObjectivesData.push_back(bonusObjectiveData); } } @@ -291,13 +307,13 @@ std::vector<WorldPackets::Achievement::CriteriaProgress> Scenario::GetCriteriasP if (!_criteriaProgress.empty()) { - for (auto critItr = _criteriaProgress.begin(); critItr != _criteriaProgress.end(); ++critItr) + for (std::pair<uint32 const, CriteriaProgress> const& progressPair : _criteriaProgress) { WorldPackets::Achievement::CriteriaProgress criteriaProgress; - criteriaProgress.Id = critItr->first; - criteriaProgress.Quantity = critItr->second.Counter; - criteriaProgress.Date = critItr->second.Date; - criteriaProgress.Player = critItr->second.PlayerGUID; + criteriaProgress.Id = progressPair.first; + criteriaProgress.Quantity = progressPair.second.Counter; + criteriaProgress.Date = progressPair.second.Date; + criteriaProgress.Player = progressPair.second.PlayerGUID; criteriasProgress.push_back(criteriaProgress); } } diff --git a/src/server/game/Scenarios/Scenario.h b/src/server/game/Scenarios/Scenario.h index 49fd3726003..596eae06077 100644 --- a/src/server/game/Scenarios/Scenario.h +++ b/src/server/game/Scenarios/Scenario.h @@ -69,6 +69,7 @@ class TC_GAME_API Scenario : public CriteriaHandler ScenarioStepState GetStepState(ScenarioStepEntry const* step); ScenarioStepEntry const* GetStep() const { return _currentstep; } ScenarioStepEntry const* GetFirstStep() const; + ScenarioStepEntry const* GetLastStep() const; void SendScenarioState(Player* player); void SendBootPlayer(Player* player); diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 9631b1c007e..628c455a0fc 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -911,6 +911,11 @@ TransactionCallback& WorldSession::AddTransactionCallback(TransactionCallback&& return _transactionCallbacks.AddCallback(std::move(callback)); } +bool WorldSession::CanAccessAlliedRaces() const +{ + return GetAccountExpansion() >= EXPANSION_BATTLE_FOR_AZEROTH; +} + void WorldSession::InitWarden(SessionKey const& k) { if (_os == "Win") diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index eb0e22b3e05..ad8bba5a316 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -989,6 +989,8 @@ class TC_GAME_API WorldSession uint8 GetExpansion() const { return m_expansion; } std::string const& GetOS() const { return _os; } + bool CanAccessAlliedRaces() const; + void InitWarden(SessionKey const& k); /// Session in auth.queue currently |