diff --git a/Source/Framework/Constants/AchievementConst.cs b/Source/Framework/Constants/AchievementConst.cs index 1f20efc67..5f1d04c0b 100644 --- a/Source/Framework/Constants/AchievementConst.cs +++ b/Source/Framework/Constants/AchievementConst.cs @@ -91,319 +91,331 @@ namespace Framework.Constants QuestObjective = 0x10 } - public enum CriteriaAdditionalCondition + public enum ModifierTreeType { - SourceDrunkValue = 1, - SourcePlayerCondition = 2, - ItemLevel = 3, - TargetCreatureEntry = 4, - TargetMustBePlayer = 5, - TargetMustBeDead = 6, - TargetMustBeEnemy = 7, - SourceHasAura = 8, - SourceHasAuraType = 9, - TargetHasAura = 10, - TargetHasAuraType = 11, - SourceAuraState = 12, - TargetAuraState = 13, - ItemQualityMin = 14, - ItemQualityEquals = 15, - SourceIsAlive = 16, - SourceAreaOrZone = 17, - TargetAreaOrZone = 18, - //Unk19 = 19, - MapDifficultyOld = 20, - TargetCreatureYieldsXp = 21, // Nyi - SourceLevelAboveTarget = 22, - SourceLevelEqualTarget = 23, - ArenaType = 24, - SourceRace = 25, - SourceClass = 26, - TargetRace = 27, - TargetClass = 28, - MaxGroupMembers = 29, - TargetCreatureType = 30, - TargetCreatureFamily = 31, - SourceMap = 32, - ClientVersion = 33, - BattlePetTeamLevel = 34, - NotInGroup = 35, - InGroup = 36, - MinPersonalRating = 37, // Nyi - TitleBitIndex = 38, - SourceLevel = 39, - TargetLevel = 40, - SourceZone = 41, - TargetZone = 42, - SourceHealthPctLower = 43, - SourceHealthPctGreater = 44, - SourceHealthPctEqual = 45, - TargetHealthPctLower = 46, - TargetHealthPctGreater = 47, - TargetHealthPctEqual = 48, - SourceHealthLower = 49, - SourceHealthGreater = 50, - SourceHealthEqual = 51, - TargetHealthLower = 52, - TargetHealthGreater = 53, - TargetHealthEqual = 54, - TargetPlayerCondition = 55, - MinAchievementPoints = 56, - InLfgDungeon = 57, - InLfgRandomDungeon = 58, - InLfgFirstRandomDungeon = 59, - //Unk60 = 60, // Nyi - RequiresGuildGroup = 61, // Nyi - GuildReputation = 62, - RatedBattleground = 63, // Nyi - RatedBattlegroundRating = 64, - ProjectRarity = 65, - ProjectRace = 66, - WorldStateExpression = 67, - MapDifficulty = 68, - SourceLevelGreater = 69, - TargetLevelGreater = 70, - SourceLevelLower = 71, - TargetLevelLower = 72, - ModifierTree = 73, - ScenarioId = 74, - TheTillersReputation = 75, - PetBattleAchievementPoints = 76, // Nyi - //Unk77 = 77, // Nyi - BattlePetFamily = 78, // Nyi - BattlePetHealthPct = 79, // Nyi - GuildGroupMembers = 80, // Nyi - BattlePetEntry = 81, // Nyi - ScenarioStepIndex = 82, - ChallengeModeMedal = 83, // Nyi - IsOnQuest = 84, - ExaltedWithFaction = 85, // Nyi - HasAchievement = 86, - HasAchievementOnCharacter = 87, // Nyi - CloudSerpentReputation = 88, - BattlePetBreedQualityId = 89, // Nyi - PetBattleIsPvp = 90, // Nyi - BattlePetSpecies = 91, - ActiveExpansion = 92, - //Unk93 = 93, // Nyi - FriendshipRepReaction = 94, // Nyi - FactionStanding = 95, - ItemClassAndSubclass = 96, // Nyi - SourceSex = 97, - SourceNativeSex = 98, - Skill = 99, - //Unk100 = 100, // Nyi - NormalPhaseShift = 101, - InPhase = 102, - NotInPhase = 103, - HasSpell = 104, - ItemCount = 105, - AccountExpansion = 106, - SourceHasAuraLabel = 107, // Nyi, Spelllabel - //Unk108 = 108, // Nyi - TimeInRange = 109, // Nyi, Packed Time Between Asset And Secondaryasset - RewardedQuest = 110, - CompletedQuest = 111, - CompletedQuestObjective = 112, // Questobjectiveid - ExploredArea = 113, - ItemCountIncludingBank = 114, - //Unk115 = 115, // Nyi - SourcePvpFactionIndex = 116, - LfgValueEqual = 117, - LfgValueGreater = 118, - CurrencyAmount = 119, - //Unk120 = 120, // Nyi - CurrencyTrackedAmount = 121, - MapInstanceType = 122, - Mentor = 123, - //Unk124 = 124, // Nyi - //Unk125 = 125, // Nyi - GarrisonLevelAbove = 126, // Asset: Garrlevel, Secondaryasset: Garrtype - GarrisonFollowersAboveLevel = 127, // Asset: Count, Secondaryasset: Followerlevel, Tertiaryasset: Garrtype - GarrisonFollowersAboveQuality = 128, // Asset: Count, Secondaryasset: Followerquality, Tertiaryasset: Garrtype - GarrisonFollowerAboveLevelWithAbility = 129, // Asset: Followerlevel, Secondaryasset: Ability, Tertiaryasset: Garrtype - GarrisonFollowerAboveLevelWithTrait = 130, // Asset: Followerlevel, Secondaryasset: Ability, Tertiaryasset: Garrtype (Same As Above But Ability Must Have GarrisonAbilityFlagTrait) - GarrisonFollowerWithAbilityInBuilding = 131, // Asset: Ability, Secondaryasset: Buildingtype, Tertiaryasset: Garrtype - GarrisonFollowerWithTraitInBuilding = 132, // Asset: Ability, Secondaryasset: Buildingtype, Tertiaryasset: Garrtype - GarrisonFollowerAboveLevelInBuilding = 133, // Asset: Followerlevel, Secondaryasset: Buildingtype, Tertiaryasset: Garrtype - GarrisonBuildingAboveLevel = 134, // Asset: Buildingtype, Secondaryasset: Buildinglevel, Tertiaryasset: Garrtype - GarrisonBlueprint = 135, // Nyi - //Unk136 = 136, // Nyi - //Unk137 = 137, // Nyi - //Unk138 = 138, // Nyi - //Unk139 = 139, // Nyi - GarrisonBuildingInactive = 140, - //Unk141 = 141, // Nyi - GarrisonBuildingEqualLevel = 142, // Asset: Buildingtype, Secondaryasset: Buildinglevel, Tertiaryasset: Garrtype - GarrisonFollowerWithAbility = 143, // Asset: Ability, Secondaryasset: Garrtype - GarrisonFollowerWithTrait = 144, // Asset: Ability, Secondaryasset: Garrtype - GarrisonFollowerAboveQualityWod = 145, // Asset: Followerquality - GarrisonFollowerEqualLevel = 146, // Asset: Followerlevel, Secondaryasset: Garrtype - GarrisonRareMission = 147, // Nyi - //Unk148 = 148, // Nyi - GarrisonBuildingLevel = 149, // Nyi - //Unk150 = 150, // Nyi - BattlePetSpeciesInTeam = 151, // Asset: Count, Secondaryasset: Battlepetspeciesid - BattlePetFamilyInTeam = 152, // Asset: Count, Secondaryasset: Battlepetfamily - //Unk153 = 153, // Nyi - //Unk154 = 154, // Nyi - //Unk155 = 155, // Nyi - //Unk156 = 156, // Nyi - GarrisonFollowerId = 157, // Follower With Id, In Any Garrison - QuestObjectiveProgressEqual = 158, // Nyi Asset: Questobjectiveid, Secondaryasset: Progress - QuestObjectiveProgressAbove = 159, // Nyi Asset: Questobjectiveid, Secondaryasset: Progress - //Unk160 = 160, // Nyi - //Unk161 = 161, // Nyi - //Unk162 = 162, // Nyi - //Unk163 = 163, // Nyi - //Unk164 = 164, // Nyi - //Unk165 = 165, // Nyi - //Unk166 = 166, // Nyi - GarrisonMissionType = 167, // Nyi - GarrisonFollowerAboveItemLevel = 168, // Asset: Followeritemlevel - GarrisonFollowersAboveItemLevel = 169, // Asset: Count, Secondaryasset: Followeritemlevel, Tertiaryasset: Garrtype - GarrisonLevelEqual = 170, // Asset: Count - GarrisonGroupSize = 171, // Nyi - //Unk172 = 172, // Nyi Something To Do With Currency But Only Used On Criterias That Require The Same Currency - TargetingCorpse = 173, - //Unk174 = 174, // Nyi - GarrisonFollowersLevelEqual = 175, // Asset: Count, Secondaryasset: Followerlevel, Tertiaryasset: Garrtype - GarrisonFollowerIdInBuilding = 176, // Asset: Followerid, Secondaryasset: Buildingtype - //Unk177 = 177, // Nyi - //Unk178 = 178, // Nyi - WorldPvpArea = 179, // Nyi - NonOwnGarrison = 180, // Nyi - //Unk181 = 181, // Nyi - //Unk182 = 183, // Nyi - //Unk183 = 183, // Nyi - GarrisonFollowersItemLevelAbove = 184, - //Unk185 = 185, // Nyi - //Unk186 = 186, // Nyi - GarrisonFollowerType = 187, // Nyi - UsedLevelBoostLessThanTwoHoursAgo = 188, // Nyi - //Unk189 = 189, // Nyi - //Unk190 = 190, // Nyi - //Unk191 = 191, // Nyi - //Unk192 = 192, // Nyi - HonorLevel = 193, - PrestigeLevel = 194, - //Unk195 = 195, // Nyi - //Unk196 = 196, // Nyi - //Unk197 = 197, // Nyi - //Unk198 = 198, // Nyi - //Unk198 = 199, // Nyi - ItemModifiedAppearance = 200, - GarrisonSelectedTalent = 201, // Nyi Asset: Garrtalentid (Talent Selected, Research Timer Doesn'T Matter) - GarrisonResearchedTalent = 202, // Nyi Asset: Garrtalentid (Talent Selected, Research Must Be Finished) - HasCharacterRestrictions = 203, - //Unk204 = 204, // Nyi - //Unk205 = 205, // Nyi - QuestInfoId = 206, - GarrisonResearchingTalent = 207, // Nyi Asset: Garrtalentid (Talent Selected, Research Must Be In Progress) - ArtifactAppearanceSetUsed = 208, - CurrencyAmountEqual = 209, - //Unk210 = 210, // Nyi - ScenarioType = 211, - AccountExpansionEqual = 212, - //Unk213 = 213, // Nyi - //Unk214 = 214, // Nyi - //Unk215 = 215, // Nyi - ChallengeModeMedal2 = 216, // Nyi Keystone Master, Asset = 3 - //Unk217 = 217, // Nyi - //Unk218 = 218, // Nyi - //Unk219 = 219, // Nyi - //Unk220 = 220, // Nyi - //Unk221 = 221, // Nyi - //Unk222 = 222, // Nyi - //Unk223 = 223, // Nyi - //Unk224 = 224, // Nyi - //Unk225 = 225, // Nyi - UsedLevelBoost = 226, // Nyi - UsedRaceChange = 227, // Nyi - UsedFactionChange = 228, // Nyi - //Unk229 = 229, // Nyi - //Unk230 = 230, // Nyi - AchievementGloballyIncompleted = 231, // Hall Of Fame Stuff, Asset: Unk, Secondaryasset: Achievementid - MainHandVisibleSubclass = 232, - OffHandVisibleSubclass = 233, - PvpTier = 234, // Nyi Asset: Pvptierid - AzeriteItemLevel = 235, - //Unk236 = 236, // Nyi - //Unk237 = 237, // Nyi - //Unk238 = 238, // Nyi - PvpTierGreater = 239, // Nyi Asset: Pvptierenum, Secondaryasset: Pvpbracket - //Unk240 = 240, // Nyi - //Unk241 = 241, // Nyi - //Unk242 = 242, // Nyi - //Unk243 = 243, // Nyi - //Unk244 = 244, // Nyi - InWarMode = 245, - //Unk246 = 246, // Nyi - KeystoneLevel = 247, // Nyi - //Unk248 = 248, // Nyi - KeystoneDungeon = 249, // Nyi Asset: Mapchallengemodeid - //Unk250 = 250, // Nyi - PvpSeason = 251, // Nyi Asset: That Unknown Column In Pvpseason.Db2 - SourceDisplayRace = 252, - TargetDisplayRace = 253, - FriendshipRepReactionExact = 254, // Nyi - SourceAuraCountEqual = 255, - TargetAuraCountEqual = 256, - SourceAuraCountGreater = 257, - TargetAuraCountGreater = 258, - UnlockedAzeriteEssenceRankLower = 259, - UnlockedAzeriteEssenceRankEqual = 260, - UnlockedAzeriteEssenceRankGreater = 261, - SourceHasAuraEffectIndex = 262, // Asset: Spellid, Secondaryasset: Index - SourceSpecializationRole = 263, - SourceLevel120 = 264, - //Unk265 = 265, - SelectedAzeriteEssenceRankLower = 266, - SelectedAzeriteEssenceRankGreater = 267, - SourceLevelInRangeCt = 268, - TargetLevelInRangeCt = 269, - //Unk270 = 270, - //Unk271 = 271, - SourceLevelGreaterCt = 272, // Compare Levels Using Content Tuning - TargetLevelGreaterCt = 273, // Compare Levels Using Content Tuning - //Unk274 = 274, - //Unk275 = 275, - //Unk276 = 276, - RafRecruitInParty = 277, // NYI - //Unk278 = 278, - //Unk279 = 279, - MapOrCosmeticMap = 280, - //Unk281 = 281, - HasEntitlement = 282, // NYI - HasQuestSession = 283, // NYI - //Unk284 = 284, - //Unk285 = 285, - //Unk286 = 286, - //Unk287 = 287, - Covenant = 288, - //Unk289 = 289, // Related To Pvp Ranking - PermanentAnimaDiversionTalent = 290, // NYI - Soulbind = 291, - //Unk292 = 292, - SourceAreaOrZoneInGroup = 293, - //Unk294 = 294, - //Unk295 = 295, - //Unk296 = 296, - //Unk297 = 297, - //Unk298 = 298, - //Unk299 = 299, - SourceInSpecificChromieTime = 300, - SourceInAnyChromieTime = 301, - //Unk302 = 302, - SourceRuneforgeLegendaryKnown = 303, - //Unk304 = 304, - //Unk305 = 305, - //Unk306 = 306, - SoulbindConduitRank = 307, // NYI - ShapeshiftFormCustomizationDisplay = 308, - SoulbindMinConduitsAtRank = 309, // NYI - IsRestrictedAccount = 310, // NYI - SourceFlying = 311, + 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 } public enum CriteriaFailEvent : byte diff --git a/Source/Framework/Constants/CliDBConst.cs b/Source/Framework/Constants/CliDBConst.cs index 5043bbb23..08ef670d0 100644 --- a/Source/Framework/Constants/CliDBConst.cs +++ b/Source/Framework/Constants/CliDBConst.cs @@ -988,6 +988,7 @@ namespace Framework.Constants Max } + [Flags] public enum BattlemasterListFlags : int { Disabled = 0x01, diff --git a/Source/Framework/Constants/PlayerConst.cs b/Source/Framework/Constants/PlayerConst.cs index 65cce0a77..4e6b65287 100644 --- a/Source/Framework/Constants/PlayerConst.cs +++ b/Source/Framework/Constants/PlayerConst.cs @@ -469,6 +469,7 @@ namespace Framework.Constants UsingPartGarrison = 0x100, CanUseObjectsMounted = 0x200, CanVisitPartyGarrison = 0x400, + WarMode = 0x800, AccountSecured = 0x1000, // Script_IsAccountSecured OverrideTransportServerTime = 0x8000, MentorRestricted = 0x20000, diff --git a/Source/Framework/Constants/SharedConst.cs b/Source/Framework/Constants/SharedConst.cs index 38a8587ca..2e3317688 100644 --- a/Source/Framework/Constants/SharedConst.cs +++ b/Source/Framework/Constants/SharedConst.cs @@ -44,6 +44,7 @@ namespace Framework.Constants public const int MaxAzeriteEmpoweredTier = 5; public const int MaxAzeriteEssenceSlot = 4; public const int MaxAzeriteEssenceRank = 4; + public const int AchivementCategoryPetBattles = 15117; /// /// BattlePets Const diff --git a/Source/Game/Achievements/AchievementManager.cs b/Source/Game/Achievements/AchievementManager.cs index ed2badc23..51ebc27a3 100644 --- a/Source/Game/Achievements/AchievementManager.cs +++ b/Source/Game/Achievements/AchievementManager.cs @@ -59,6 +59,11 @@ namespace Game.Achievements return _achievementPoints; } + public ICollection GetCompletedAchievementIds() + { + return _completedAchievements.Keys; + } + public override bool CanUpdateCriteriaTree(Criteria criteria, CriteriaTree tree, Player referencePlayer) { AchievementRecord achievement = tree.Achievement; diff --git a/Source/Game/Achievements/CriteriaHandler.cs b/Source/Game/Achievements/CriteriaHandler.cs index 291da6d60..6b339313e 100644 --- a/Source/Game/Achievements/CriteriaHandler.cs +++ b/Source/Game/Achievements/CriteriaHandler.cs @@ -1251,23 +1251,23 @@ namespace Game.Achievements int secondaryAsset = modifier.SecondaryAsset; int tertiaryAsset = modifier.TertiaryAsset; - switch ((CriteriaAdditionalCondition)modifier.Type) + switch ((ModifierTreeType)modifier.Type) { - case CriteriaAdditionalCondition.SourceDrunkValue: // 1 + case ModifierTreeType.PlayerInebriationLevelEqualOrGreaterThan: // 1 { uint inebriation = (uint)Math.Min(Math.Max(referencePlayer.GetDrunkValue(), referencePlayer.m_playerData.FakeInebriation), 100); if (inebriation < reqValue) return false; break; } - case CriteriaAdditionalCondition.SourcePlayerCondition: // 2 + case ModifierTreeType.PlayerMeetsCondition: // 2 { PlayerConditionRecord playerCondition = CliDB.PlayerConditionStorage.LookupByKey(reqValue); if (playerCondition == null || !ConditionManager.IsPlayerMeetingCondition(referencePlayer, playerCondition)) return false; break; } - case CriteriaAdditionalCondition.ItemLevel: // 3 + case ModifierTreeType.MinimumItemLevel: // 3 { // miscValue1 is itemid ItemTemplate item = Global.ObjectMgr.GetItemTemplate((uint)miscValue1); @@ -1275,47 +1275,47 @@ namespace Game.Achievements return false; break; } - case CriteriaAdditionalCondition.TargetCreatureEntry: // 4 + case ModifierTreeType.TargetCreatureId: // 4 if (unit == null || unit.GetEntry() != reqValue) return false; break; - case CriteriaAdditionalCondition.TargetMustBePlayer: // 5 + case ModifierTreeType.TargetIsPlayer: // 5 if (unit == null || !unit.IsTypeId(TypeId.Player)) return false; break; - case CriteriaAdditionalCondition.TargetMustBeDead: // 6 + case ModifierTreeType.TargetIsDead: // 6 if (unit == null || unit.IsAlive()) return false; break; - case CriteriaAdditionalCondition.TargetMustBeEnemy: // 7 + case ModifierTreeType.TargetIsOppositeFaction: // 7 if (unit == null || !referencePlayer.IsHostileTo(unit)) return false; break; - case CriteriaAdditionalCondition.SourceHasAura: // 8 + case ModifierTreeType.PlayerHasAura: // 8 if (!referencePlayer.HasAura(reqValue)) return false; break; - case CriteriaAdditionalCondition.SourceHasAuraType: // 9 + case ModifierTreeType.PlayerHasAuraEffect: // 9 if (!referencePlayer.HasAuraType((AuraType)reqValue)) return false; break; - case CriteriaAdditionalCondition.TargetHasAura: // 10 + case ModifierTreeType.TargetHasAura: // 10 if (unit == null || !unit.HasAura(reqValue)) return false; break; - case CriteriaAdditionalCondition.TargetHasAuraType: // 11 + case ModifierTreeType.TargetHasAuraEffect: // 11 if (unit == null || !unit.HasAuraType((AuraType)reqValue)) return false; break; - case CriteriaAdditionalCondition.SourceAuraState: // 12 + case ModifierTreeType.TargetHasAuraState: // 12 + if (unit == null || !unit.HasAuraState((AuraStateType)reqValue)) + return false; + break; + case ModifierTreeType.PlayerHasAuraState: // 13 if (!referencePlayer.HasAuraState((AuraStateType)reqValue)) return false; break; - case CriteriaAdditionalCondition.TargetAuraState: // 13 - if (!unit || !unit.HasAuraState((AuraStateType)reqValue)) - return false; - break; - case CriteriaAdditionalCondition.ItemQualityMin: // 14 + case ModifierTreeType.ItemQualityIsAtLeast: // 14 { // miscValue1 is itemid ItemTemplate item = Global.ObjectMgr.GetItemTemplate((uint)miscValue1); @@ -1323,7 +1323,7 @@ namespace Game.Achievements return false; break; } - case CriteriaAdditionalCondition.ItemQualityEquals: // 15 + case ModifierTreeType.ItemQualityIsExactly: // 15 { // miscValue1 is itemid ItemTemplate item = Global.ObjectMgr.GetItemTemplate((uint)miscValue1); @@ -1331,11 +1331,11 @@ namespace Game.Achievements return false; break; } - case CriteriaAdditionalCondition.SourceIsAlive: // 16 + case ModifierTreeType.PlayerIsAlive: // 16 if (referencePlayer.IsDead()) return false; break; - case CriteriaAdditionalCondition.SourceAreaOrZone: // 17 + case ModifierTreeType.PlayerIsInArea: // 17 { uint zoneId, areaId; referencePlayer.GetZoneAndAreaId(out zoneId, out areaId); @@ -1343,7 +1343,7 @@ namespace Game.Achievements return false; break; } - case CriteriaAdditionalCondition.TargetAreaOrZone: // 18 + case ModifierTreeType.TargetIsInArea: // 18 { if (unit == null) return false; @@ -1353,49 +1353,57 @@ namespace Game.Achievements return false; break; } - case CriteriaAdditionalCondition.MapDifficultyOld: // 20 + case ModifierTreeType.ItemId: // 19 + if (miscValue1 != reqValue) + return false; + break; + case ModifierTreeType.LegacyDungeonDifficulty: // 20 { DifficultyRecord difficulty = CliDB.DifficultyStorage.LookupByKey(referencePlayer.GetMap().GetDifficultyID()); if (difficulty == null || difficulty.OldEnumValue == -1 || difficulty.OldEnumValue != reqValue) return false; break; } - case CriteriaAdditionalCondition.SourceLevelAboveTarget: // 22 + case ModifierTreeType.PlayerToTargetLevelDeltaGreaterThan: // 21 + if (unit == null || referencePlayer.GetLevel() < unit.GetLevel() + reqValue) + return false; + break; + case ModifierTreeType.TargetToPlayerLevelDeltaGreaterThan: // 22 if (!unit || referencePlayer.GetLevel() + reqValue < unit.GetLevel()) return false; break; - case CriteriaAdditionalCondition.SourceLevelEqualTarget: // 23 + case ModifierTreeType.PlayerLevelEqualTargetLevel: // 23 if (!unit || referencePlayer.GetLevel() != unit.GetLevel()) return false; break; - case CriteriaAdditionalCondition.ArenaType: // 24 + case ModifierTreeType.PlayerInArenaWithTeamSize: // 24 { Battleground bg = referencePlayer.GetBattleground(); if (!bg || !bg.IsArena() || bg.GetArenaType() != (ArenaTypes)reqValue) return false; break; } - case CriteriaAdditionalCondition.SourceRace: // 25 + case ModifierTreeType.PlayerRace: // 25 if ((uint)referencePlayer.GetRace() != reqValue) return false; break; - case CriteriaAdditionalCondition.SourceClass: // 26 + case ModifierTreeType.PlayerClass: // 26 if ((uint)referencePlayer.GetClass() != reqValue) return false; break; - case CriteriaAdditionalCondition.TargetRace: // 27 + case ModifierTreeType.TargetRace: // 27 if (unit == null || !unit.IsTypeId(TypeId.Player) || (uint)unit.GetRace() != reqValue) return false; break; - case CriteriaAdditionalCondition.TargetClass: // 28 + case ModifierTreeType.TargetClass: // 28 if (unit == null || !unit.IsTypeId(TypeId.Player) || (uint)unit.GetClass() != reqValue) return false; break; - case CriteriaAdditionalCondition.MaxGroupMembers: // 29 + case ModifierTreeType.LessThanTappers: // 29 if (referencePlayer.GetGroup() && referencePlayer.GetGroup().GetMembersCount() >= reqValue) return false; break; - case CriteriaAdditionalCondition.TargetCreatureType: // 30 + case ModifierTreeType.CreatureType: // 30 { if (unit == null) return false; @@ -1404,7 +1412,7 @@ namespace Game.Achievements return false; break; } - case CriteriaAdditionalCondition.TargetCreatureFamily: // 31 + case ModifierTreeType.CreatureFamily: // 31 { if (!unit) return false; @@ -1412,40 +1420,44 @@ namespace Game.Achievements return false; break; } - case CriteriaAdditionalCondition.SourceMap: // 32 + case ModifierTreeType.PlayerMap: // 32 if (referencePlayer.GetMapId() != reqValue) return false; break; - case CriteriaAdditionalCondition.ClientVersion: // 33 + case ModifierTreeType.ClientVersionEqualOrLessThan: // 33 if (reqValue < Global.RealmMgr.GetMinorMajorBugfixVersionForBuild(Global.WorldMgr.GetRealm().Build)) return false; break; - case CriteriaAdditionalCondition.BattlePetTeamLevel: // 34 + case ModifierTreeType.BattlePetTeamLevel: // 34 foreach (BattlePetSlot slot in referencePlayer.GetSession().GetBattlePetMgr().GetSlots()) - if (slot.Pet.Level != reqValue) + if (slot.Pet.Level < reqValue) return false; break; - case CriteriaAdditionalCondition.NotInGroup: // 35 + case ModifierTreeType.PlayerIsNotInParty: // 35 if (referencePlayer.GetGroup()) return false; break; - case CriteriaAdditionalCondition.InGroup: // 36 + case ModifierTreeType.PlayerIsInParty: // 36 if (!referencePlayer.GetGroup()) return false; break; - case CriteriaAdditionalCondition.TitleBitIndex: // 38 // miscValue1 is title's bit index - if (miscValue1 != reqValue) + case ModifierTreeType.HasPersonalRatingEqualOrGreaterThan: // 37 + if (referencePlayer.GetMaxPersonalArenaRatingRequirement(0) < reqValue) return false; break; - case CriteriaAdditionalCondition.SourceLevel: // 39 + case ModifierTreeType.HasTitle: // 38 + if (!referencePlayer.HasTitle(reqValue)) + return false; + break; + case ModifierTreeType.PlayerLevelEqual: // 39 if (referencePlayer.GetLevel() != reqValue) return false; break; - case CriteriaAdditionalCondition.TargetLevel: // 40 + case ModifierTreeType.TargetLevelEqual: // 40 if (unit == null || unit.GetLevelForTarget(referencePlayer) != reqValue) return false; break; - case CriteriaAdditionalCondition.SourceZone: // 41 + case ModifierTreeType.PlayerIsInZone: // 41 { uint zoneId = referencePlayer.GetAreaId(); AreaTableRecord areaEntry = CliDB.AreaTableStorage.LookupByKey(zoneId); @@ -1456,7 +1468,7 @@ namespace Game.Achievements return false; break; } - case CriteriaAdditionalCondition.TargetZone: // 42 + case ModifierTreeType.TargetIsInZone: // 42 { if (!unit) return false; @@ -1469,55 +1481,55 @@ namespace Game.Achievements return false; break; } - case CriteriaAdditionalCondition.SourceHealthPctLower: // 43 + case ModifierTreeType.PlayerHealthBelowPercent: // 43 if (referencePlayer.GetHealthPct() > (float)reqValue) return false; break; - case CriteriaAdditionalCondition.SourceHealthPctGreater: // 44 + case ModifierTreeType.PlayerHealthAbovePercent: // 44 if (referencePlayer.GetHealthPct() < (float)reqValue) return false; break; - case CriteriaAdditionalCondition.SourceHealthPctEqual: // 45 + case ModifierTreeType.PlayerHealthEqualsPercent: // 45 if (referencePlayer.GetHealthPct() != (float)reqValue) return false; break; - case CriteriaAdditionalCondition.TargetHealthPctLower: // 46 + case ModifierTreeType.TargetHealthBelowPercent: // 46 if (unit == null || unit.GetHealthPct() >= (float)reqValue) return false; break; - case CriteriaAdditionalCondition.TargetHealthPctGreater: // 47 + case ModifierTreeType.TargetHealthAbovePercent: // 47 if (!unit || unit.GetHealthPct() < (float)reqValue) return false; break; - case CriteriaAdditionalCondition.TargetHealthPctEqual: // 48 + case ModifierTreeType.TargetHealthEqualsPercent: // 48 if (!unit || unit.GetHealthPct() != (float)reqValue) return false; break; - case CriteriaAdditionalCondition.SourceHealthLower: // 49 + case ModifierTreeType.PlayerHealthBelowValue: // 49 if (referencePlayer.GetHealth() > reqValue) return false; break; - case CriteriaAdditionalCondition.SourceHealthGreater: // 50 + case ModifierTreeType.PlayerHealthAboveValue: // 50 if (referencePlayer.GetHealth() < reqValue) return false; break; - case CriteriaAdditionalCondition.SourceHealthEqual: // 51 + case ModifierTreeType.PlayerHealthEqualsValue: // 51 if (referencePlayer.GetHealth() != reqValue) return false; break; - case CriteriaAdditionalCondition.TargetHealthLower: // 52 + case ModifierTreeType.TargetHealthBelowValue: // 52 if (!unit || unit.GetHealth() > reqValue) return false; break; - case CriteriaAdditionalCondition.TargetHealthGreater: // 53 + case ModifierTreeType.TargetHealthAboveValue: // 53 if (!unit || unit.GetHealth() < reqValue) return false; break; - case CriteriaAdditionalCondition.TargetHealthEqual: // 54 + case ModifierTreeType.TargetHealthEqualsValue: // 54 if (!unit || unit.GetHealth() != reqValue) return false; break; - case CriteriaAdditionalCondition.TargetPlayerCondition: // 55 + case ModifierTreeType.TargetIsPlayerAndMeetsCondition: // 55 { if (unit == null || !unit.IsPlayer()) return false; @@ -1527,78 +1539,150 @@ namespace Game.Achievements return false; break; } - case CriteriaAdditionalCondition.MinAchievementPoints: // 56 + case ModifierTreeType.PlayerHasMoreThanAchievementPoints: // 56 if (referencePlayer.GetAchievementPoints() <= reqValue) return false; break; - case CriteriaAdditionalCondition.InLfgDungeon: // 57 + case ModifierTreeType.PlayerInLfgDungeon: // 57 if (ConditionManager.GetPlayerConditionLfgValue(referencePlayer, PlayerConditionLfgStatus.InLFGDungeon) == 0) return false; break; - case CriteriaAdditionalCondition.InLfgRandomDungeon: // 58 + case ModifierTreeType.PlayerInRandomLfgDungeon: // 58 if (ConditionManager.GetPlayerConditionLfgValue(referencePlayer, PlayerConditionLfgStatus.InLFGRandomDungeon) == 0) return false; break; - case CriteriaAdditionalCondition.InLfgFirstRandomDungeon: // 59 + case ModifierTreeType.PlayerInFirstRandomLfgDungeon: // 59 if (ConditionManager.GetPlayerConditionLfgValue(referencePlayer, PlayerConditionLfgStatus.InLFGFirstRandomDungeon) == 0) return false; break; - case CriteriaAdditionalCondition.GuildReputation: // 62 + case ModifierTreeType.PlayerInRankedArenaMatch: // 60 + { + Battleground bg = referencePlayer.GetBattleground(); + if (bg == null || !bg.IsArena() || !bg.IsRated()) + return false; + break; + } + case ModifierTreeType.PlayerInGuildParty: // 61 NYI + return false; + case ModifierTreeType.PlayerGuildReputationEqualOrGreaterThan: // 62 if (referencePlayer.GetReputationMgr().GetReputation(1168) < reqValue) return false; break; - case CriteriaAdditionalCondition.RatedBattlegroundRating: // 64 + case ModifierTreeType.PlayerInRatedBattleground: // 63 + { + Battleground bg = referencePlayer.GetBattleground(); + if (bg == null || !bg.IsBattleground() || !bg.IsRated()) + return false; + break; + } + case ModifierTreeType.PlayerBattlegroundRatingEqualOrGreaterThan: // 64 if (referencePlayer.GetRBGPersonalRating() < reqValue) return false; break; - case CriteriaAdditionalCondition.WorldStateExpression: // 67 + case ModifierTreeType.ResearchProjectRarity: // 65 NYI + case ModifierTreeType.ResearchProjectBranch: // 66 NYI + return false; + case ModifierTreeType.WorldStateExpression: // 67 WorldStateExpressionRecord worldStateExpression = CliDB.WorldStateExpressionStorage.LookupByKey(reqValue); if (worldStateExpression != null) return ConditionManager.IsPlayerMeetingExpression(referencePlayer, worldStateExpression); return false; - case CriteriaAdditionalCondition.MapDifficulty: // 68 - { - DifficultyRecord difficulty = CliDB.DifficultyStorage.LookupByKey(referencePlayer.GetMap().GetDifficultyID()); - if (difficulty == null || difficulty.Id != reqValue) - return false; - break; - } - case CriteriaAdditionalCondition.SourceLevelGreater: // 69 + case ModifierTreeType.DungeonDifficulty: // 68 + if (referencePlayer.GetMap().GetDifficultyID() != (Difficulty)reqValue) + return false; + break; + case ModifierTreeType.PlayerLevelEqualOrGreaterThan: // 69 if (referencePlayer.GetLevel() < reqValue) return false; break; - case CriteriaAdditionalCondition.TargetLevelGreater: // 70 + case ModifierTreeType.TargetLevelEqualOrGreaterThan: // 70 if (!unit || unit.GetLevel() < reqValue) return false; break; - case CriteriaAdditionalCondition.SourceLevelLower: // 71 + case ModifierTreeType.PlayerLevelEqualOrLessThan: // 71 if (referencePlayer.GetLevel() > reqValue) return false; break; - case CriteriaAdditionalCondition.TargetLevelLower: // 72 + case ModifierTreeType.TargetLevelEqualOrLessThan: // 72 if (!unit || unit.GetLevel() > reqValue) return false; break; - case CriteriaAdditionalCondition.ModifierTree: // 73 + case ModifierTreeType.ModifierTree: // 73 ModifierTreeNode nextModifierTree = Global.CriteriaMgr.GetModifierTree(reqValue); if (nextModifierTree != null) return ModifierTreeSatisfied(nextModifierTree, miscValue1, miscValue2, unit, referencePlayer); return false; - case CriteriaAdditionalCondition.ScenarioId: // 74 + case ModifierTreeType.PlayerScenario: // 74 { Scenario scenario = referencePlayer.GetScenario(); - if (scenario == null) - return false; - - if (scenario.GetEntry().Id != reqValue) + if (scenario == null || scenario.GetEntry().Id != reqValue) return false; break; } - case CriteriaAdditionalCondition.TheTillersReputation: // 75 + case ModifierTreeType.TillersReputationGreaterThan: // 75 if (referencePlayer.GetReputationMgr().GetReputation(1272) < reqValue) return false; break; - case CriteriaAdditionalCondition.ScenarioStepIndex: // 82 + case ModifierTreeType.BattlePetAchievementPointsEqualOrGreaterThan: // 76 + { + short getRootAchievementCategory(AchievementRecord achievement) + { + short category = (short)achievement.Category; + do + { + var categoryEntry = CliDB.AchievementCategoryStorage.LookupByKey(category); + if (categoryEntry?.Parent == -1) + break; + + category = categoryEntry.Parent; + } while (true); + + return category; + } + + uint petAchievementPoints = 0; + foreach (uint achievementId in referencePlayer.GetCompletedAchievementIds()) + { + var achievement = CliDB.AchievementStorage.LookupByKey(achievementId); + if (getRootAchievementCategory(achievement) == SharedConst.AchivementCategoryPetBattles) + petAchievementPoints += 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 + { + var speciesEntry = CliDB.BattlePetSpeciesStorage.LookupByKey(miscValue1); + if (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 + { + uint guildMemberCount = 0; + var group = referencePlayer.GetGroup(); + if (group != null) + { + for (var itr = group.GetFirstMember(); itr != null; 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 scenario = referencePlayer.GetScenario(); if (scenario == null) @@ -1608,82 +1692,135 @@ namespace Game.Achievements return false; break; } - case CriteriaAdditionalCondition.IsOnQuest: // 84 + case ModifierTreeType.ChallengeModeMedal: // 83 + return false; // OBSOLETE + case ModifierTreeType.PlayerOnQuest: // 84 if (referencePlayer.FindQuestSlot(reqValue) == SharedConst.MaxQuestLogSize) return false; break; - case CriteriaAdditionalCondition.ExaltedWithFaction: // 85 + case ModifierTreeType.ExaltedWithFaction: // 85 if (referencePlayer.GetReputationMgr().GetReputation(reqValue) < 42000) return false; break; - case CriteriaAdditionalCondition.HasAchievement: // 86 - case CriteriaAdditionalCondition.HasAchievementOnCharacter: // 87 + case ModifierTreeType.EarnedAchievementOnAccount: // 86 + case ModifierTreeType.EarnedAchievementOnPlayer: // 87 if (!referencePlayer.HasAchieved(reqValue)) return false; break; - case CriteriaAdditionalCondition.CloudSerpentReputation: // 88 + case ModifierTreeType.OrderOfTheCloudSerpentReputationGreaterThan: // 88 if (referencePlayer.GetReputationMgr().GetReputation(1271) < reqValue) return false; break; - case CriteriaAdditionalCondition.BattlePetSpecies: // 91 + case ModifierTreeType.BattlePetQuality: // 89 NYI + case ModifierTreeType.BattlePetFightWasPVP: // 90 NYI + return false; + case ModifierTreeType.BattlePetSpecies: // 91 if (miscValue1 != reqValue) return false; break; - case CriteriaAdditionalCondition.ActiveExpansion: // 92 - if ((int)referencePlayer.GetSession().GetExpansion() < reqValue) + case ModifierTreeType.ServerExpansionEqualOrGreaterThan: // 92 + if (WorldConfig.GetIntValue(WorldCfg.Expansion) < reqValue) return false; break; - case CriteriaAdditionalCondition.FactionStanding: // 95 + case ModifierTreeType.PlayerHasBattlePetJournalLock: // 93 + if (!referencePlayer.GetSession().GetBattlePetMgr().HasJournalLock()) + return false; + break; + case ModifierTreeType.FriendshipRepReactionIsMet: // 94 + { + var friendshipRepReaction = CliDB.FriendshipRepReactionStorage.LookupByKey(reqValue); + if (friendshipRepReaction == null) + return false; + + var friendshipReputation = CliDB.FriendshipReputationStorage.LookupByKey(friendshipRepReaction.FriendshipRepID); + if (friendshipReputation == null) + return false; + + if (referencePlayer.GetReputation((uint)friendshipReputation.FactionID) < friendshipRepReaction.ReactionThreshold) + return false; + break; + } + case ModifierTreeType.ReputationWithFactionIsEqualOrGreaterThan: // 95 if (referencePlayer.GetReputationMgr().GetReputation(reqValue) < reqValue) return false; break; - case CriteriaAdditionalCondition.SourceSex: // 97 + case ModifierTreeType.ItemClassAndSubclass: // 96 + { + ItemTemplate item = Global.ObjectMgr.GetItemTemplate((uint)miscValue1); + if (item == null || item.GetClass() != (ItemClass)reqValue || item.GetSubClass() != secondaryAsset) + return false; + break; + } + case ModifierTreeType.PlayerGender: // 97 if ((int)referencePlayer.GetGender() != reqValue) return false; break; - case CriteriaAdditionalCondition.SourceNativeSex: // 98 + case ModifierTreeType.PlayerNativeGender: // 98 if (referencePlayer.GetNativeSex() != (Gender)reqValue) return false; break; - case CriteriaAdditionalCondition.Skill: // 99 + case ModifierTreeType.PlayerSkillEqualOrGreaterThan: // 99 if (referencePlayer.GetPureSkillValue((SkillType)reqValue) < secondaryAsset) return false; break; - case CriteriaAdditionalCondition.NormalPhaseShift: // 101 + case ModifierTreeType.PlayerLanguageSkillEqualOrGreaterThan: // 100 + { + var languageDescs = Global.LanguageMgr.GetLanguageDescById((Language)reqValue); + if (!languageDescs.Any(desc => referencePlayer.GetSkillValue((SkillType)desc.SkillId) >= secondaryAsset)) + return false; + break; + } + case ModifierTreeType.PlayerIsInNormalPhase: // 101 if (!PhasingHandler.InDbPhaseShift(referencePlayer, 0, 0, 0)) return false; break; - case CriteriaAdditionalCondition.InPhase: // 102 + case ModifierTreeType.PlayerIsInPhase: // 102 if (!PhasingHandler.InDbPhaseShift(referencePlayer, 0, (ushort)reqValue, 0)) return false; break; - case CriteriaAdditionalCondition.NotInPhase: // 103 - if (PhasingHandler.InDbPhaseShift(referencePlayer, 0, (ushort)reqValue, 0)) + case ModifierTreeType.PlayerIsInPhaseGroup: // 103 + if (!PhasingHandler.InDbPhaseShift(referencePlayer, 0, 0, reqValue)) return false; break; - case CriteriaAdditionalCondition.HasSpell: // 104 + case ModifierTreeType.PlayerKnowsSpell: // 104 if (!referencePlayer.HasSpell(reqValue)) return false; break; - case CriteriaAdditionalCondition.ItemCount: // 105 + case ModifierTreeType.PlayerHasItemQuantity: // 105 if (referencePlayer.GetItemCount(reqValue, false) < secondaryAsset) return false; break; - case CriteriaAdditionalCondition.AccountExpansion: // 106 - if ((int)referencePlayer.GetSession().GetAccountExpansion() < reqValue) + case ModifierTreeType.PlayerExpansionLevelEqualOrGreaterThan: // 106 + if (referencePlayer.GetSession().GetExpansion() < (Expansion)reqValue) return false; break; - case CriteriaAdditionalCondition.RewardedQuest: // 110 + case ModifierTreeType.PlayerHasAuraWithLabel: // 107 + if (!referencePlayer.HasAura(aura => aura.GetSpellInfo().HasLabel(reqValue))) + return false; + break; + case ModifierTreeType.PlayersRealmWorldState: // 108 + if (Global.WorldMgr.GetWorldState(reqValue) != secondaryAsset) + return false; + break; + case ModifierTreeType.TimeBetween: // 109 + { + long from = Time.GetUnixTimeFromPackedTime(reqValue); + long to = Time.GetUnixTimeFromPackedTime((uint)secondaryAsset); + if (GameTime.GetGameTime() < from || GameTime.GetGameTime() > to) + return false; + break; + } + case ModifierTreeType.PlayerHasCompletedQuest: // 110 uint questBit = Global.DB2Mgr.GetQuestUniqueBitFlag(reqValue); if (questBit != 0) if ((referencePlayer.m_activePlayerData.QuestCompleted[((int)questBit - 1) >> 6] & (1ul << (((int)questBit - 1) & 63))) == 0) return false; break; - case CriteriaAdditionalCondition.CompletedQuest: // 111 + case ModifierTreeType.PlayerIsReadyToTurnInQuest: // 111 if (referencePlayer.GetQuestStatus(reqValue) != QuestStatus.Complete) return false; break; - case CriteriaAdditionalCondition.CompletedQuestObjective: // 112 + case ModifierTreeType.PlayerHasCompletedQuestObjective: // 112 { QuestObjective objective = Global.ObjectMgr.GetQuestObjective(reqValue); if (objective == null) @@ -1698,7 +1835,7 @@ namespace Game.Achievements return false; break; } - case CriteriaAdditionalCondition.ExploredArea: // 113 + case ModifierTreeType.PlayerHasExploredArea: // 113 { AreaTableRecord areaTable = CliDB.AreaTableStorage.LookupByKey(reqValue); if (areaTable == null) @@ -1715,11 +1852,15 @@ namespace Game.Achievements return false; break; } - case CriteriaAdditionalCondition.ItemCountIncludingBank: // 114 + case ModifierTreeType.PlayerHasItemQuantityIncludingBank: // 114 if (referencePlayer.GetItemCount(reqValue, true) < secondaryAsset) return false; break; - case CriteriaAdditionalCondition.SourcePvpFactionIndex: // 116 + case ModifierTreeType.Weather: // 115 + if (referencePlayer.GetMap().GetZoneWeather(referencePlayer.GetZoneId()) != (WeatherState)reqValue) + return false; + break; + case ModifierTreeType.PlayerFaction: // 116 { ChrRacesRecord race = CliDB.ChrRacesStorage.LookupByKey(referencePlayer.GetRace()); if (race == null) @@ -1740,86 +1881,105 @@ namespace Game.Achievements return false; break; } - case CriteriaAdditionalCondition.LfgValueEqual: // 117 + case ModifierTreeType.LfgStatusEqual: // 117 if (ConditionManager.GetPlayerConditionLfgValue(referencePlayer, (PlayerConditionLfgStatus)reqValue) != secondaryAsset) return false; break; - case CriteriaAdditionalCondition.LfgValueGreater: // 118 + case ModifierTreeType.LFgStatusEqualOrGreaterThan: // 118 if (ConditionManager.GetPlayerConditionLfgValue(referencePlayer, (PlayerConditionLfgStatus)reqValue) < secondaryAsset) return false; break; - case CriteriaAdditionalCondition.CurrencyAmount: // 119 + case ModifierTreeType.PlayerHasCurrencyEqualOrGreaterThan: // 119 if (!referencePlayer.HasCurrency(reqValue, (uint)secondaryAsset)) return false; break; - case CriteriaAdditionalCondition.CurrencyTrackedAmount: // 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 CriteriaAdditionalCondition.MapInstanceType: // 122 + case ModifierTreeType.PlayerMapInstanceType: // 122 if ((uint)referencePlayer.GetMap().GetEntry().InstanceType != reqValue) return false; break; - case CriteriaAdditionalCondition.Mentor: // 123 + case ModifierTreeType.PlayerInTimeWalkerInstance: // 123 if (!referencePlayer.HasPlayerFlag(PlayerFlags.Timewalking)) return false; break; - case CriteriaAdditionalCondition.GarrisonLevelAbove: // 126 + case ModifierTreeType.PvpSeasonIsActive: // 124 + if (!WorldConfig.GetBoolValue(WorldCfg.ArenaSeasonInProgress)) + return false; + break; + case ModifierTreeType.PvpSeason: // 125 + if (WorldConfig.GetIntValue(WorldCfg.ArenaSeasonId) != reqValue) + return false; + break; + case ModifierTreeType.GarrisonTierEqualOrGreaterThan: // 126 { Garrison garrison = referencePlayer.GetGarrison(); if (garrison == null || garrison.GetGarrisonType() != (GarrisonType)secondaryAsset || garrison.GetSiteLevel().GarrLevel < reqValue) return false; break; } - case CriteriaAdditionalCondition.GarrisonFollowersAboveLevel: // 127 + case ModifierTreeType.GarrisonFollowersWithLevelEqualOrGreaterThan: // 127 { Garrison garrison = referencePlayer.GetGarrison(); - if (garrison == null || garrison.GetGarrisonType() != (GarrisonType)tertiaryAsset) + if (garrison == null) return false; uint followerCount = garrison.CountFollowers(follower => { - return follower.PacketInfo.FollowerLevel >= secondaryAsset; + var garrFollower = CliDB.GarrFollowerStorage.LookupByKey(follower.PacketInfo.GarrFollowerID); + return garrFollower?.GarrFollowerTypeID == tertiaryAsset && follower.PacketInfo.FollowerLevel >= secondaryAsset; }); if (followerCount < reqValue) return false; break; } - case CriteriaAdditionalCondition.GarrisonFollowersAboveQuality: // 128 + case ModifierTreeType.GarrisonFollowersWithQualityEqualOrGreaterThan: // 128 { Garrison garrison = referencePlayer.GetGarrison(); - if (garrison == null || garrison.GetGarrisonType() != (GarrisonType)tertiaryAsset) + if (garrison == null) return false; uint followerCount = garrison.CountFollowers(follower => { - return follower.PacketInfo.Quality >= secondaryAsset; + var garrFollower = CliDB.GarrFollowerStorage.LookupByKey(follower.PacketInfo.GarrFollowerID); + return garrFollower?.GarrFollowerTypeID == tertiaryAsset && follower.PacketInfo.Quality >= secondaryAsset; }); if (followerCount < reqValue) return false; break; } - case CriteriaAdditionalCondition.GarrisonFollowerAboveLevelWithAbility: // 129 + case ModifierTreeType.GarrisonFollowerWithAbilityAtLevelEqualOrGreaterThan: // 129 { Garrison garrison = referencePlayer.GetGarrison(); - if (garrison == null || garrison.GetGarrisonType() != (GarrisonType)tertiaryAsset) + if (garrison == null) return false; uint followerCount = garrison.CountFollowers(follower => { - return follower.PacketInfo.FollowerLevel >= reqValue && follower.HasAbility((uint)secondaryAsset); + var garrFollower = CliDB.GarrFollowerStorage.LookupByKey(follower.PacketInfo.GarrFollowerID); + return garrFollower?.GarrFollowerTypeID == tertiaryAsset && follower.PacketInfo.FollowerLevel >= reqValue && follower.HasAbility((uint)secondaryAsset); }); if (followerCount < 1) return false; break; } - case CriteriaAdditionalCondition.GarrisonFollowerAboveLevelWithTrait: // 130 + case ModifierTreeType.GarrisonFollowerWithTraitAtLevelEqualOrGreaterThan: // 130 { Garrison garrison = referencePlayer.GetGarrison(); - if (garrison == null || garrison.GetGarrisonType() != (GarrisonType)tertiaryAsset) + if (garrison == null) return false; GarrAbilityRecord traitEntry = CliDB.GarrAbilityStorage.LookupByKey(secondaryAsset); @@ -1828,14 +1988,15 @@ namespace Game.Achievements uint followerCount = garrison.CountFollowers(follower => { - return follower.PacketInfo.FollowerLevel >= reqValue && follower.HasAbility((uint)secondaryAsset); + var garrFollower = CliDB.GarrFollowerStorage.LookupByKey(follower.PacketInfo.GarrFollowerID); + return garrFollower?.GarrFollowerTypeID == tertiaryAsset && follower.PacketInfo.FollowerLevel >= reqValue && follower.HasAbility((uint)secondaryAsset); }); if (followerCount < 1) return false; break; } - case CriteriaAdditionalCondition.GarrisonFollowerWithAbilityInBuilding: // 131 + case ModifierTreeType.GarrisonFollowerWithAbilityAssignedToBuilding: // 131 { Garrison garrison = referencePlayer.GetGarrison(); if (garrison == null || garrison.GetGarrisonType() != (GarrisonType)tertiaryAsset) @@ -1854,7 +2015,7 @@ namespace Game.Achievements return false; break; } - case CriteriaAdditionalCondition.GarrisonFollowerWithTraitInBuilding: // 132 + case ModifierTreeType.GarrisonFollowerWithTraitAssignedToBuilding: // 132 { Garrison garrison = referencePlayer.GetGarrison(); if (garrison == null || garrison.GetGarrisonType() != (GarrisonType)tertiaryAsset) @@ -1877,7 +2038,7 @@ namespace Game.Achievements return false; break; } - case CriteriaAdditionalCondition.GarrisonFollowerAboveLevelInBuilding: // 133 + case ModifierTreeType.GarrisonFollowerWithLevelAssignedToBuilding: // 133 { Garrison garrison = referencePlayer.GetGarrison(); if (garrison == null || garrison.GetGarrisonType() != (GarrisonType)tertiaryAsset) @@ -1898,7 +2059,7 @@ namespace Game.Achievements return false; break; } - case CriteriaAdditionalCondition.GarrisonBuildingAboveLevel: // 134 + case ModifierTreeType.GarrisonBuildingWithLevelEqualOrGreaterThan: // 134 { Garrison garrison = referencePlayer.GetGarrison(); if (garrison == null || garrison.GetGarrisonType() != (GarrisonType)tertiaryAsset) @@ -1917,21 +2078,36 @@ namespace Game.Achievements } return false; } - case CriteriaAdditionalCondition.GarrisonBlueprint: // 135 + case ModifierTreeType.HasBlueprintForGarrisonBuilding: // 135 { - GarrBuildingRecord blueprintBuilding = CliDB.GarrBuildingStorage.LookupByKey(reqValue); - if (blueprintBuilding == null) - return false; - Garrison garrison = referencePlayer.GetGarrison(); - if (garrison == null || garrison.GetGarrisonType() != (GarrisonType)blueprintBuilding.GarrTypeID) + if (garrison == null || garrison.GetGarrisonType() != (GarrisonType)secondaryAsset) return false; if (!garrison.HasBlueprint(reqValue)) return false; break; } - case CriteriaAdditionalCondition.GarrisonBuildingInactive: // 140 + case ModifierTreeType.HasGarrisonBuildingSpecialization: // 136 + return false; // OBSOLETE + case ModifierTreeType.AllGarrisonPlotsAreFull: // 137 + { + Garrison garrison = referencePlayer.GetGarrison(); + if (garrison == null || garrison.GetGarrisonType() != (GarrisonType)reqValue) + return false; + + foreach (var plot in garrison.GetPlots()) + if (!plot.BuildingInfo.PacketInfo.HasValue) + 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 { GarrBuildingRecord building = CliDB.GarrBuildingStorage.LookupByKey(reqValue); if (building == null) @@ -1950,7 +2126,9 @@ namespace Game.Achievements } return false; } - case CriteriaAdditionalCondition.GarrisonBuildingEqualLevel: // 142 + case ModifierTreeType.GarrisonMissionHasBeenCompleted: // 141 NYI + return false; + case ModifierTreeType.GarrisonBuildingLevelEqual: // 142 { Garrison garrison = referencePlayer.GetGarrison(); if (garrison == null || garrison.GetGarrisonType() != (GarrisonType)tertiaryAsset) @@ -1962,14 +2140,14 @@ namespace Game.Achievements continue; GarrBuildingRecord building = CliDB.GarrBuildingStorage.LookupByKey(plot.BuildingInfo.PacketInfo.Value.GarrBuildingID); - if (building == null || building.UpgradeLevel != reqValue || building.BuildingType != secondaryAsset) + if (building == null || building.UpgradeLevel != secondaryAsset || building.BuildingType != reqValue) continue; return true; } return false; } - case CriteriaAdditionalCondition.GarrisonFollowerWithAbility: // 143 + case ModifierTreeType.GarrisonFollowerHasAbility: // 143 { Garrison garrison = referencePlayer.GetGarrison(); if (garrison == null || garrison.GetGarrisonType() != (GarrisonType)secondaryAsset) @@ -1996,7 +2174,7 @@ namespace Game.Achievements } break; } - case CriteriaAdditionalCondition.GarrisonFollowerWithTrait: // 144 + case ModifierTreeType.GarrisonFollowerHasTrait: // 144 { GarrAbilityRecord traitEntry = CliDB.GarrAbilityStorage.LookupByKey(reqValue); if (traitEntry == null || !traitEntry.Flags.HasAnyFlag(GarrisonAbilityFlags.Trait)) @@ -2024,7 +2202,7 @@ namespace Game.Achievements } break; } - case CriteriaAdditionalCondition.GarrisonFollowerAboveQualityWod: // 145 + case ModifierTreeType.GarrisonFollowerQualityEqual: // 145 { Garrison garrison = referencePlayer.GetGarrison(); if (garrison == null || garrison.GetGarrisonType() != GarrisonType.Garrison) @@ -2048,7 +2226,7 @@ namespace Game.Achievements } break; } - case CriteriaAdditionalCondition.GarrisonFollowerEqualLevel: // 146 + case ModifierTreeType.GarrisonFollowerLevelEqual: // 146 { Garrison garrison = referencePlayer.GetGarrison(); if (garrison == null || garrison.GetGarrisonType() != (GarrisonType)secondaryAsset) @@ -2057,14 +2235,14 @@ namespace Game.Achievements if (miscValue1 != 0) { Garrison.Follower follower = garrison.GetFollower(miscValue1); - if (follower == null || follower.PacketInfo.FollowerLevel < reqValue) + if (follower == null || follower.PacketInfo.FollowerLevel != reqValue) return false; } else { uint followerCount = garrison.CountFollowers(follower => { - return follower.PacketInfo.FollowerLevel >= reqValue; + return follower.PacketInfo.FollowerLevel == reqValue; }); if (followerCount < 1) @@ -2072,7 +2250,46 @@ namespace Game.Achievements } break; } - case CriteriaAdditionalCondition.BattlePetSpeciesInTeam: // 151 + case ModifierTreeType.GarrisonMissionIsRare: // 147 NYI + case ModifierTreeType.GarrisonMissionIsElite: // 148 NYI + return false; + case ModifierTreeType.CurrentGarrisonBuildingLevelEqual: // 149 + { + if (miscValue1 == 0) + return false; + + Garrison garrison = referencePlayer.GetGarrison(); + if (garrison == null) + return false; + + foreach (var plot in garrison.GetPlots()) + { + if (!plot.BuildingInfo.PacketInfo.HasValue || plot.BuildingInfo.PacketInfo.Value.GarrBuildingID != miscValue1) + continue; + + var building = CliDB.GarrBuildingStorage.LookupByKey(plot.BuildingInfo.PacketInfo.Value.GarrBuildingID); + if (building == null || building.UpgradeLevel != reqValue) + continue; + + return true; + } + break; + } + case ModifierTreeType.GarrisonPlotInstanceHasBuildingThatIsReadyToActivate: // 150 + { + Garrison garrison = referencePlayer.GetGarrison(); + if (garrison == null) + return false; + + var plot = garrison.GetPlot(reqValue); + if (plot == null) + return false; + + if (!plot.BuildingInfo.CanActivate() || !plot.BuildingInfo.PacketInfo.HasValue || plot.BuildingInfo.PacketInfo.Value.Active) + return false; + break; + } + case ModifierTreeType.BattlePetTeamWithSpeciesEqualOrGreaterThan: // 151 { uint count = 0; foreach (BattlePetSlot slot in referencePlayer.GetSession().GetBattlePetMgr().GetSlots()) @@ -2083,7 +2300,7 @@ namespace Game.Achievements return false; break; } - case CriteriaAdditionalCondition.BattlePetFamilyInTeam: // 152 + case ModifierTreeType.BattlePetTeamWithTypeEqualOrGreaterThan: // 152 { uint count = 0; foreach (BattlePetSlot slot in referencePlayer.GetSession().GetBattlePetMgr().GetSlots()) @@ -2098,129 +2315,238 @@ namespace Game.Achievements return false; break; } - case CriteriaAdditionalCondition.GarrisonFollowerId: // 157 + case ModifierTreeType.PetBattleLastAbility: // 153 NYI + case ModifierTreeType.PetBattleLastAbilityType: // 154 NYI + return false; + case ModifierTreeType.BattlePetTeamWithAliveEqualOrGreaterThan: // 155 + { + uint count = 0; + foreach (var slot in 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 garrison = referencePlayer.GetGarrison(); if (garrison == null) return false; - if (miscValue1 != 0) - { - Garrison.Follower follower = garrison.GetFollower(miscValue1); - if (follower == null || follower.PacketInfo.GarrFollowerID != reqValue) - return false; - } - else - { - uint followerCount = garrison.CountFollowers(follower => - { - return follower.PacketInfo.GarrFollowerID == reqValue; - }); - - if (followerCount < 1) - return false; - } - break; - } - case CriteriaAdditionalCondition.GarrisonFollowerAboveItemLevel: // 168 - { - Garrison garrison = referencePlayer.GetGarrison(); - if (garrison == null) - return false; - - if (miscValue1 != 0) - { - Garrison.Follower follower = garrison.GetFollower(miscValue1); - if (follower == null || follower.PacketInfo.GarrFollowerID != reqValue) - return false; - } - else - { - uint followerCount = garrison.CountFollowers(follower => - { - return follower.GetItemLevel() >= reqValue; - }); - - if (followerCount < 1) - return false; - } - break; - } - case CriteriaAdditionalCondition.GarrisonFollowersAboveItemLevel: // 169 - { - Garrison garrison = referencePlayer.GetGarrison(); - if (garrison == null || garrison.GetGarrisonType() != (GarrisonType)tertiaryAsset) - return false; - uint followerCount = garrison.CountFollowers(follower => { - return follower.GetItemLevel() >= secondaryAsset; - }); - - if (followerCount < reqValue) - return false; - - break; - } - - - case CriteriaAdditionalCondition.GarrisonLevelEqual: // 170 - { - Garrison garrison = referencePlayer.GetGarrison(); - if (garrison == null || garrison.GetGarrisonType() != GarrisonType.Garrison || garrison.GetSiteLevel().GarrLevel != reqValue) - return false; - break; - } - case CriteriaAdditionalCondition.TargetingCorpse: // 173 - if (referencePlayer.GetTarget().GetHigh() != HighGuid.Corpse) - return false; - break; - case CriteriaAdditionalCondition.GarrisonFollowersLevelEqual: // 175 - { - Garrison garrison = referencePlayer.GetGarrison(); - if (garrison == null || garrison.GetGarrisonType() != (GarrisonType)tertiaryAsset) - return false; - - uint followerCount = garrison.CountFollowers(follower => - { - return follower.PacketInfo.FollowerLevel >= secondaryAsset; - }); - - if (followerCount < reqValue) - return false; - break; - } - case CriteriaAdditionalCondition.GarrisonFollowerIdInBuilding: // 176 - { - Garrison garrison = referencePlayer.GetGarrison(); - if (garrison == null || garrison.GetGarrisonType() != GarrisonType.Garrison) - return false; - - uint followerCount = garrison.CountFollowers(follower => - { - if (follower.PacketInfo.GarrFollowerID != reqValue) - return false; - - GarrBuildingRecord followerBuilding = CliDB.GarrBuildingStorage.LookupByKey(follower.PacketInfo.CurrentBuildingID); - if (followerBuilding == null) - return false; - - return followerBuilding.BuildingType == secondaryAsset; + return follower.PacketInfo.GarrFollowerID == reqValue; }); if (followerCount < 1) return false; break; } - case CriteriaAdditionalCondition.WorldPvpArea: // 179 + case ModifierTreeType.PlayerQuestObjectiveProgressEqual: // 158 { - BattleField bf = Global.BattleFieldMgr.GetBattlefieldToZoneId(referencePlayer.GetZoneId()); - if (bf == null || bf.GetBattleId() != reqValue) + QuestObjective objective = Global.ObjectMgr.GetQuestObjective(reqValue); + if (objective == null) + return false; + + if (referencePlayer.GetQuestObjectiveData(objective) != secondaryAsset) return false; break; } + case ModifierTreeType.PlayerQuestObjectiveProgressEqualOrGreaterThan: // 159 + { + QuestObjective objective = Global.ObjectMgr.GetQuestObjective(reqValue); + if (objective == null) + return false; - case CriteriaAdditionalCondition.GarrisonFollowersItemLevelAbove: // 184 + if (referencePlayer.GetQuestObjectiveData(objective) < 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 == null || garrison.GetGarrisonType() != (GarrisonType)reqValue) + return false; + + foreach (var plot in garrison.GetPlots()) + { + if (!plot.BuildingInfo.PacketInfo.HasValue) + return false; + + var building = CliDB.GarrBuildingStorage.LookupByKey(plot.BuildingInfo.PacketInfo.Value.GarrBuildingID); + if (building == null || building.UpgradeLevel != reqValue) + return false; + } + break; + } + case ModifierTreeType.GarrisonMissionType: // 167 NYI + return false; + case ModifierTreeType.GarrisonFollowerItemLevelEqualOrGreaterThan: // 168 + { + if (miscValue1 == 0) + return false; + + Garrison garrison = referencePlayer.GetGarrison(); + if (garrison == null) + return false; + + uint followerCount = garrison.CountFollowers(follower => + { + return follower.PacketInfo.GarrFollowerID == miscValue1 && follower.GetItemLevel() >= reqValue; + }); + + if (followerCount < 1) + return false; + break; + } + case ModifierTreeType.GarrisonFollowerCountWithItemLevelEqualOrGreaterThan: // 169 + { + Garrison garrison = referencePlayer.GetGarrison(); + if (garrison == null) + return false; + + uint followerCount = garrison.CountFollowers(follower => + { + var garrFollower = CliDB.GarrFollowerStorage.LookupByKey(follower.PacketInfo.GarrFollowerID); + return garrFollower?.GarrFollowerTypeID == tertiaryAsset && follower.GetItemLevel() >= secondaryAsset; + }); + + if (followerCount < reqValue) + return false; + + break; + } + case ModifierTreeType.GarrisonTierEqual: // 170 + { + Garrison garrison = referencePlayer.GetGarrison(); + if (garrison == null || garrison.GetGarrisonType() != (GarrisonType)secondaryAsset || garrison.GetSiteLevel().GarrLevel != reqValue) + return false; + break; + } + case ModifierTreeType.InstancePlayerCountEqual: // 171 + if (referencePlayer.GetMap().GetPlayers().Count != 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 ModifierTreeType.PlayerCanAcceptQuest: // 174 + { + Quest quest = Global.ObjectMgr.GetQuestTemplate(reqValue); + if (quest == null) + return false; + + if (!referencePlayer.CanTakeQuest(quest, false)) + return false; + break; + } + case ModifierTreeType.GarrisonFollowerCountWithLevelEqualOrGreaterThan: // 175 + { + Garrison garrison = referencePlayer.GetGarrison(); + if (garrison == null || garrison.GetGarrisonType() != (GarrisonType)tertiaryAsset) + return false; + + uint followerCount = garrison.CountFollowers(follower => + { + var garrFollower = CliDB.GarrFollowerStorage.LookupByKey(follower.PacketInfo.GarrFollowerID); + return garrFollower?.GarrFollowerTypeID == tertiaryAsset && follower.PacketInfo.FollowerLevel == secondaryAsset; + }); + + if (followerCount < reqValue) + return false; + break; + } + case ModifierTreeType.GarrisonFollowerIsInBuilding: // 176 + { + Garrison garrison = referencePlayer.GetGarrison(); + if (garrison == null) + return false; + + uint followerCount = garrison.CountFollowers(follower => + { + return follower.PacketInfo.GarrFollowerID == reqValue && follower.PacketInfo.CurrentBuildingID == secondaryAsset; + }); + + if (followerCount < 1) + return false; + break; + } + case ModifierTreeType.GarrisonMissionCountLessThan: // 177 NYI + return false; + case ModifierTreeType.GarrisonPlotInstanceCountEqualOrGreaterThan: // 178 + { + Garrison garrison = referencePlayer.GetGarrison(); + if (garrison == null || garrison.GetGarrisonType() != (GarrisonType)reqValue) + return false; + + uint plotCount = 0; + foreach (var plot in garrison.GetPlots()) + { + var garrPlotInstance = CliDB.GarrPlotInstanceStorage.LookupByKey(plot.PacketInfo.GarrPlotInstanceID); + if (garrPlotInstance == null || 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 garrison = referencePlayer.GetGarrison(); + if (garrison == null) + return false; + + uint followerCount = garrison.CountFollowers(follower => follower.PacketInfo.GarrFollowerID == reqValue && (follower.PacketInfo.FollowerStatus & (byte)GarrisonFollowerStatus.Inactive) == 0); + if (followerCount < 1) + return false; + break; + } + case ModifierTreeType.PlayerDailyRandomValueMod_X_Equals: // 182 NYI + return false; + case ModifierTreeType.PlayerHasMount: // 183 + { + foreach (var pair in referencePlayer.GetSession().GetCollectionMgr().GetAccountMounts()) + { + var mount = Global.DB2Mgr.GetMount(pair.Key); + if (mount == null) + continue; + + if (mount.Id == reqValue) + return true; + } + return false; + } + case ModifierTreeType.GarrisonFollowerCountWithInactiveWithItemLevelEqualOrGreaterThan: // 184 { Garrison garrison = referencePlayer.GetGarrison(); if (garrison == null) @@ -2239,54 +2565,110 @@ namespace Game.Achievements return false; break; } - case CriteriaAdditionalCondition.UsedLevelBoostLessThanTwoHoursAgo: // 188 + case ModifierTreeType.GarrisonFollowerIsOnAMission: // 185 + { + Garrison garrison = referencePlayer.GetGarrison(); + if (garrison == null) + return false; + + uint followerCount = garrison.CountFollowers(follower => follower.PacketInfo.GarrFollowerID == reqValue && follower.PacketInfo.CurrentMissionID != 0); + if (followerCount < 1) + return false; + break; + } + case ModifierTreeType.GarrisonMissionCountInSetLessThan: // 186 NYI return false; - case CriteriaAdditionalCondition.HonorLevel: // 193 - if (referencePlayer.GetHonorLevel() != reqValue) + case ModifierTreeType.GarrisonFollowerType: // 187 + { + var garrFollower = CliDB.GarrFollowerStorage.LookupByKey(miscValue1); + if (garrFollower == null || 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(PlayerFlagsEx.MercenaryMode)) return false; break; - case CriteriaAdditionalCondition.PrestigeLevel: // 194 + case ModifierTreeType.PlayerEffectiveRace: // 191 NYI + case ModifierTreeType.TargetEffectiveRace: // 192 NYI return false; - case CriteriaAdditionalCondition.ItemModifiedAppearance: // 200 + case ModifierTreeType.HonorLevelEqualOrGreaterThan: // 193 + if (referencePlayer.GetHonorLevel() < reqValue) + return false; + break; + case ModifierTreeType.PrestigeLevelEqualOrGreaterThan: // 194 + return false; // OBSOLOTE + case ModifierTreeType.GarrisonMissionIsReadyToCollect: // 195 NYI + case ModifierTreeType.PlayerIsInstanceOwner: // 196 NYI + return false; + case ModifierTreeType.PlayerHasHeirloom: // 197 + if (!referencePlayer.GetSession().GetCollectionMgr().GetAccountHeirlooms().ContainsKey(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 { var (PermAppearance, TempAppearance) = referencePlayer.GetSession().GetCollectionMgr().HasItemAppearance(reqValue); if (!PermAppearance || TempAppearance) return false; break; } - case CriteriaAdditionalCondition.HasCharacterRestrictions: // 203 + case ModifierTreeType.GarrisonTalentSelected: // 201 NYI + case ModifierTreeType.GarrisonTalentResearched: // 202 NYI + return false; + case ModifierTreeType.PlayerHasRestriction: // 203 { - if (referencePlayer.m_activePlayerData.CharacterRestrictions.Empty()) + int restrictionIndex = referencePlayer.m_activePlayerData.CharacterRestrictions.FindIndexIf(restriction => restriction.Type == reqValue); + if (restrictionIndex < 0) return false; break; } - case CriteriaAdditionalCondition.QuestInfoId: // 206 + case ModifierTreeType.PlayerCreatedCharacterLessThanHoursAgoRealTime: // 204 NYI + return false; + case ModifierTreeType.PlayerCreatedCharacterLessThanHoursAgoGameTime: // 205 + if (TimeSpan.FromHours(reqValue) >= TimeSpan.FromSeconds(referencePlayer.GetTotalPlayedTime())) + return false; + break; + case ModifierTreeType.QuestHasQuestInfoId: // 206 { Quest quest = Global.ObjectMgr.GetQuestTemplate((uint)miscValue1); if (quest == null || quest.Id != reqValue) return false; break; } - case CriteriaAdditionalCondition.ArtifactAppearanceSetUsed: // 208 + case ModifierTreeType.GarrisonTalentResearchInProgress: // 207 NYI + return false; + case ModifierTreeType.PlayerEquippedArtifactAppearanceSet: // 208 { - for (byte slot = EquipmentSlot.MainHand; slot <= EquipmentSlot.Ranged; ++slot) + Aura artifactAura = referencePlayer.GetAura(PlayerConst.ArtifactsAllWeaponsGeneralWeaponEquippedPassive); + if (artifactAura != null) { - Item artifact = referencePlayer.GetItemByPos(InventorySlots.Bag0, slot); + Item artifact = referencePlayer.GetItemByGuid(artifactAura.GetCastItemGUID()); if (artifact != null) { ArtifactAppearanceRecord artifactAppearance = CliDB.ArtifactAppearanceStorage.LookupByKey(artifact.GetModifier(ItemModifier.ArtifactAppearanceId)); if (artifactAppearance != null) if (artifactAppearance.ArtifactAppearanceSetID == reqValue) - return true; + break; } } return false; } - case CriteriaAdditionalCondition.CurrencyAmountEqual: // 209 + case ModifierTreeType.PlayerHasCurrencyEqual: // 209 if (referencePlayer.GetCurrency(reqValue) != secondaryAsset) return false; break; - case CriteriaAdditionalCondition.ScenarioType: // 211 + case ModifierTreeType.MinimumAverageItemHighWaterMarkForSpec: // 210 NYI + return false; + case ModifierTreeType.PlayerScenarioType: // 211 { Scenario scenario = referencePlayer.GetScenario(); if (scenario == null) @@ -2296,48 +2678,321 @@ namespace Game.Achievements return false; break; } - case CriteriaAdditionalCondition.AccountExpansionEqual: // 212 - if ((uint)referencePlayer.GetSession().GetAccountExpansion() != reqValue) + case ModifierTreeType.PlayersAuthExpansionLevelEqualOrGreaterThan: // 212 + if (referencePlayer.GetSession().GetAccountExpansion() < (Expansion)reqValue) return false; break; - case CriteriaAdditionalCondition.AchievementGloballyIncompleted: // 231 + case ModifierTreeType.PlayerLastWeek2v2Rating: // 213 NYI + case ModifierTreeType.PlayerLastWeek3v3Rating: // 214 NYI + case ModifierTreeType.PlayerLastWeekRBGRating: // 215 NYI + return false; + case ModifierTreeType.GroupMemberCountFromConnectedRealmEqualOrGreaterThan: // 216 { - AchievementRecord achievement = CliDB.AchievementStorage.LookupByKey(secondaryAsset); - if (achievement == null) + uint memberCount = 0; + var group = referencePlayer.GetGroup(); + if (group != null) + { + for (var itr = group.GetFirstMember(); itr != null; 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 artifact = referencePlayer.GetItemByEntry((uint)secondaryAsset, ItemSearchLocation.Everywhere); + if (artifact == null) return false; - if (Global.AchievementMgr.IsRealmCompleted(achievement)) + if (artifact.GetTotalUnlockedArtifactPowers() < reqValue) return false; break; } - case CriteriaAdditionalCondition.MainHandVisibleSubclass: // 232 + case ModifierTreeType.ParagonReputationLevelEqualOrGreaterThan: // 218 + if (referencePlayer.GetReputationMgr().GetParagonLevel((uint)miscValue1) < reqValue) + return false; + return false; + case ModifierTreeType.GarrisonShipmentIsReady: // 219 NYI + return false; + case ModifierTreeType.PlayerIsInPvpBrawl: // 220 { + var bg = CliDB.BattlemasterListStorage.LookupByKey(referencePlayer.GetBattlegroundTypeId()); + if (bg == null || !bg.Flags.HasFlag(BattlemasterListFlags.Brawl)) + return false; + break; + } + case ModifierTreeType.ParagonReputationLevelWithFactionEqualOrGreaterThan: // 221 + { + var faction = CliDB.FactionStorage.LookupByKey(secondaryAsset); + if (faction == null) + return false; + + if (referencePlayer.GetReputationMgr().GetParagonLevel(faction.ParagonFactionID) < reqValue) + return false; + break; + } + case ModifierTreeType.PlayerHasItemWithBonusListFromTreeAndQuality: // 222 + { + var bonusListIDs = Global.DB2Mgr.GetAllItemBonusTreeBonuses(reqValue); + if (bonusListIDs.Empty()) + return false; + + bool bagScanReachedEnd = referencePlayer.ForEachItem(ItemSearchLocation.Everywhere, item => + { + bool hasBonus = item.m_itemData.BonusListIDs._value.Any(bonusListID => bonusListIDs.Contains(bonusListID)); + return !hasBonus; + }); + + if (bagScanReachedEnd) + return false; + break; + } + case ModifierTreeType.PlayerHasEmptyInventorySlotCountEqualOrGreaterThan: // 223 + if (referencePlayer.GetFreeInventorySlotCount(ItemSearchLocation.Inventory) < reqValue) + return false; + break; + case ModifierTreeType.PlayerHasItemInHistoryOfProgressiveEvent: // 224 NYI + return false; + case ModifierTreeType.PlayerHasArtifactPowerRankCountPurchasedEqualOrGreaterThan: // 225 + { + Aura artifactAura = referencePlayer.GetAura(PlayerConst.ArtifactsAllWeaponsGeneralWeaponEquippedPassive); + if (artifactAura == null) + return false; + + Item artifact = referencePlayer.GetItemByGuid(artifactAura.GetCastItemGUID()); + if (!artifact) + return false; + + var artifactPower = artifact.GetArtifactPower((uint)secondaryAsset); + if (artifactPower == null) + return false; + + if (artifactPower.PurchasedRank < reqValue) + return false; + break; + } + 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 + { + var group = referencePlayer.GetGroup(); + if (group != null) + { + uint membersWithAchievement = 0; + for (var itr = group.GetFirstMember(); itr != null; itr = itr.Next()) + if (itr.GetSource().HasAchieved((uint)secondaryAsset)) + ++membersWithAchievement; + + if (membersWithAchievement > reqValue) + return false; + } + // true if no group + break; + } + case ModifierTreeType.PlayerMainhandWeaponType: // 232 + { + var visibleItem = referencePlayer.m_playerData.VisibleItems[EquipmentSlot.MainHand]; uint itemSubclass = (uint)ItemSubClassWeapon.Fist; - ItemTemplate itemTemplate = Global.ObjectMgr.GetItemTemplate(referencePlayer.m_playerData.VisibleItems[EquipmentSlot.MainHand].ItemID); + ItemTemplate itemTemplate = Global.ObjectMgr.GetItemTemplate(visibleItem.ItemID); if (itemTemplate != null) - itemSubclass = itemTemplate.GetSubClass(); + { + if (itemTemplate.GetClass() == ItemClass.Weapon) + { + itemSubclass = itemTemplate.GetSubClass(); + + var itemModifiedAppearance = Global.DB2Mgr.GetItemModifiedAppearance(visibleItem.ItemID, visibleItem.ItemAppearanceModID); + if (itemModifiedAppearance != null) + { + var itemModifiedAppearaceExtra = CliDB.ItemModifiedAppearanceExtraStorage.LookupByKey(itemModifiedAppearance.Id); + if (itemModifiedAppearaceExtra != null) + if (itemModifiedAppearaceExtra.DisplayWeaponSubclassID > 0) + itemSubclass = (uint)itemModifiedAppearaceExtra.DisplayWeaponSubclassID; + } + } + } if (itemSubclass != reqValue) return false; break; } - case CriteriaAdditionalCondition.OffHandVisibleSubclass: // 233 + case ModifierTreeType.PlayerOffhandWeaponType: // 233 { + var visibleItem = referencePlayer.m_playerData.VisibleItems[EquipmentSlot.OffHand]; uint itemSubclass = (uint)ItemSubClassWeapon.Fist; - ItemTemplate itemTemplate = Global.ObjectMgr.GetItemTemplate(referencePlayer.m_playerData.VisibleItems[EquipmentSlot.OffHand].ItemID); + ItemTemplate itemTemplate = Global.ObjectMgr.GetItemTemplate(visibleItem.ItemID); if (itemTemplate != null) - itemSubclass = itemTemplate.GetSubClass(); + { + if (itemTemplate.GetClass() == ItemClass.Weapon) + { + itemSubclass = itemTemplate.GetSubClass(); + + var itemModifiedAppearance = Global.DB2Mgr.GetItemModifiedAppearance(visibleItem.ItemID, visibleItem.ItemAppearanceModID); + if (itemModifiedAppearance != null) + { + var itemModifiedAppearaceExtra = CliDB.ItemModifiedAppearanceExtraStorage.LookupByKey(itemModifiedAppearance.Id); + if (itemModifiedAppearaceExtra != null) + if (itemModifiedAppearaceExtra.DisplayWeaponSubclassID > 0) + itemSubclass = (uint)itemModifiedAppearaceExtra.DisplayWeaponSubclassID; + } + } + } if (itemSubclass != reqValue) return false; break; } - case CriteriaAdditionalCondition.AzeriteItemLevel: // 235 + case ModifierTreeType.PlayerPvpTier: // 234 + { + var pvpTier = CliDB.PvpTierStorage.LookupByKey(reqValue); + if (pvpTier == null) + return false; + + if (pvpTier.BracketID >= referencePlayer.m_activePlayerData.PvpInfo.GetSize()) + return false; + + var pvpInfo = referencePlayer.m_activePlayerData.PvpInfo[pvpTier.BracketID]; + if (pvpTier.Id != pvpInfo.PvpTierID || pvpInfo.Disqualified) + return false; + break; + } + case ModifierTreeType.PlayerAzeriteLevelEqualOrGreaterThan: // 235 { Item heartOfAzeroth = referencePlayer.GetItemByEntry(PlayerConst.ItemIdHeartOfAzeroth, ItemSearchLocation.Everywhere); if (!heartOfAzeroth || heartOfAzeroth.ToAzeriteItem().GetLevel() < reqValue) return false; break; } - case CriteriaAdditionalCondition.SourceDisplayRace: // 252 + case ModifierTreeType.PlayerIsOnQuestInQuestline: // 236 + { + bool isOnQuest = false; + var questLineQuests = Global.DB2Mgr.GetQuestsForQuestLine(reqValue); + if (!questLineQuests.Empty()) + isOnQuest = questLineQuests.Any(questLineQuest => referencePlayer.FindQuestSlot(questLineQuest.QuestID) < SharedConst.MaxQuestLogSize); + + if (!isOnQuest) + return false; + break; + } + case ModifierTreeType.PlayerIsQnQuestLinkedToScheduledWorldStateGroup: // 237 + return false; // OBSOLETE (db2 removed) + case ModifierTreeType.PlayerIsInRaidGroup: // 238 + { + var group = referencePlayer.GetGroup(); + if (group == null || !group.IsRaidGroup()) + return false; + + break; + } + case ModifierTreeType.PlayerPvpTierInBracketEqualOrGreaterThan: // 239 + { + if (secondaryAsset >= referencePlayer.m_activePlayerData.PvpInfo.GetSize()) + return false; + + var pvpInfo = referencePlayer.m_activePlayerData.PvpInfo[secondaryAsset]; + var pvpTier = CliDB.PvpTierStorage.LookupByKey(pvpInfo.PvpTierID); + if (pvpTier == null) + return false; + + if (pvpTier.Rank < reqValue) + return false; + break; + } + case ModifierTreeType.PlayerCanAcceptQuestInQuestline: // 240 + { + var questLineQuests = Global.DB2Mgr.GetQuestsForQuestLine(reqValue); + if (questLineQuests.Empty()) + return false; + + bool canTakeQuest = questLineQuests.Any(questLineQuest => + { + Quest quest = Global.ObjectMgr.GetQuestTemplate(questLineQuest.QuestID); + if (quest != null) + return referencePlayer.CanTakeQuest(quest, false); + + return false; + }); + + if (!canTakeQuest) + return false; + break; + } + case ModifierTreeType.PlayerHasCompletedQuestline: // 241 + { + var questLineQuests = Global.DB2Mgr.GetQuestsForQuestLine(reqValue); + if (questLineQuests.Empty()) + return false; + + foreach (var questLineQuest in questLineQuests) + if (!referencePlayer.GetQuestRewardStatus(questLineQuest.QuestID)) + return false; + break; + } + case ModifierTreeType.PlayerHasCompletedQuestlineQuestCount: // 242 + { + var questLineQuests = Global.DB2Mgr.GetQuestsForQuestLine(reqValue); + if (questLineQuests.Empty()) + return false; + + uint completedQuests = 0; + foreach (var questLineQuest in questLineQuests) + if (referencePlayer.GetQuestRewardStatus(questLineQuest.QuestID)) + ++completedQuests; + + if (completedQuests < reqValue) + return false; + break; + } + case ModifierTreeType.PlayerHasCompletedPercentageOfQuestline: // 243 + { + var questLineQuests = Global.DB2Mgr.GetQuestsForQuestLine(reqValue); + if (questLineQuests.Empty()) + return false; + + int completedQuests = 0; + foreach (var questLineQuest in questLineQuests) + if (referencePlayer.GetQuestRewardStatus(questLineQuest.QuestID)) + ++completedQuests; + + if (MathFunctions.GetPctOf(completedQuests, questLineQuests.Count) < reqValue) + return false; + break; + } + case ModifierTreeType.PlayerHasWarModeEnabled: // 244 + if (!referencePlayer.HasPlayerLocalFlag(PlayerLocalFlags.WarMode)) + return false; + break; + case ModifierTreeType.PlayerIsOnWarModeShard: // 245 + if (!referencePlayer.HasPlayerFlag(PlayerFlags.WarModeActive)) + 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 { CreatureDisplayInfoRecord creatureDisplayInfo = CliDB.CreatureDisplayInfoStorage.LookupByKey(referencePlayer.GetDisplayId()); if (creatureDisplayInfo == null) @@ -2351,7 +3006,7 @@ namespace Game.Achievements return false; break; } - case CriteriaAdditionalCondition.TargetDisplayRace: // 253 + case ModifierTreeType.TargetVisibleRace: // 253 { if (!unit) return false; @@ -2367,23 +3022,45 @@ namespace Game.Achievements return false; break; } - case CriteriaAdditionalCondition.SourceAuraCountEqual: // 255 + case ModifierTreeType.FriendshipRepReactionEqual: // 254 + { + var friendshipRepReaction = CliDB.FriendshipRepReactionStorage.LookupByKey(reqValue); + if (friendshipRepReaction == null) + return false; + + var friendshipReputation = CliDB.FriendshipReputationStorage.LookupByKey(friendshipRepReaction.FriendshipRepID); + if (friendshipReputation == null) + return false; + + var friendshipReactions = Global.DB2Mgr.GetFriendshipRepReactions(reqValue); + if (friendshipReactions == null) + return false; + + int rank = (int)referencePlayer.GetReputationRank((uint)friendshipReputation.FactionID); + if (rank >= friendshipReactions.Count) + return false; + + if (friendshipReactions[rank].Id != reqValue) + return false; + break; + } + case ModifierTreeType.PlayerAuraStackCountEqual: // 255 if (referencePlayer.GetAuraCount((uint)secondaryAsset) != reqValue) return false; break; - case CriteriaAdditionalCondition.TargetAuraCountEqual: // 256 + case ModifierTreeType.TargetAuraStackCountEqual: // 256 if (!unit || unit.GetAuraCount((uint)secondaryAsset) != reqValue) return false; break; - case CriteriaAdditionalCondition.SourceAuraCountGreater: // 257 + case ModifierTreeType.PlayerAuraStackCountEqualOrGreaterThan: // 257 if (referencePlayer.GetAuraCount((uint)secondaryAsset) < reqValue) return false; break; - case CriteriaAdditionalCondition.TargetAuraCountGreater: // 258 + case ModifierTreeType.TargetAuraStackCountEqualOrGreaterThan: // 258 if (!unit || unit.GetAuraCount((uint)secondaryAsset) < reqValue) return false; break; - case CriteriaAdditionalCondition.UnlockedAzeriteEssenceRankLower: // 259 + case ModifierTreeType.PlayerHasAzeriteEssenceRankLessThan: // 259 { Item heartOfAzeroth = referencePlayer.GetItemByEntry(PlayerConst.ItemIdHeartOfAzeroth, ItemSearchLocation.Everywhere); if (heartOfAzeroth != null) @@ -2398,7 +3075,7 @@ namespace Game.Achievements } return false; } - case CriteriaAdditionalCondition.UnlockedAzeriteEssenceRankEqual: // 260 + case ModifierTreeType.PlayerHasAzeriteEssenceRankEqual: // 260 { Item heartOfAzeroth = referencePlayer.GetItemByEntry(PlayerConst.ItemIdHeartOfAzeroth, ItemSearchLocation.Everywhere); if (heartOfAzeroth != null) @@ -2413,7 +3090,7 @@ namespace Game.Achievements } return false; } - case CriteriaAdditionalCondition.UnlockedAzeriteEssenceRankGreater: // 261 + case ModifierTreeType.PlayerHasAzeriteEssenceRankGreaterThan: // 261 { Item heartOfAzeroth = referencePlayer.GetItemByEntry(PlayerConst.ItemIdHeartOfAzeroth, ItemSearchLocation.Everywhere); if (heartOfAzeroth != null) @@ -2428,22 +3105,32 @@ namespace Game.Achievements } return false; } - case CriteriaAdditionalCondition.SourceHasAuraEffectIndex: // 262 + case ModifierTreeType.PlayerHasAuraWithEffectIndex: // 262 if (referencePlayer.GetAuraEffect(reqValue, (uint)secondaryAsset) == null) return false; break; - case CriteriaAdditionalCondition.SourceSpecializationRole: // 263 + case ModifierTreeType.PlayerLootSpecializationMatchesRole: // 263 { ChrSpecializationRecord spec = CliDB.ChrSpecializationStorage.LookupByKey(referencePlayer.GetPrimarySpecialization()); if (spec == null || spec.Role != reqValue) return false; break; } - case CriteriaAdditionalCondition.SourceLevel120: // 264 - if (referencePlayer.GetLevel() != 60) + case ModifierTreeType.PlayerIsAtMaxExpansionLevel: // 264 + if (referencePlayer.GetLevel() != Global.ObjectMgr.GetMaxLevelForExpansion((Expansion)WorldConfig.GetIntValue(WorldCfg.Expansion))) return false; break; - case CriteriaAdditionalCondition.SelectedAzeriteEssenceRankLower: // 266 + case ModifierTreeType.TransmogSource: // 265 + { + var itemModifiedAppearance = CliDB.ItemModifiedAppearanceStorage.LookupByKey(miscValue2); + if (itemModifiedAppearance == null) + return false; + + if (itemModifiedAppearance.TransmogSourceTypeEnum != reqValue) + return false; + break; + } + case ModifierTreeType.PlayerHasAzeriteEssenceInSlotAtRankLessThan: // 266 { Item heartOfAzeroth = referencePlayer.GetItemByEntry(PlayerConst.ItemIdHeartOfAzeroth, ItemSearchLocation.Everywhere); if (heartOfAzeroth != null) @@ -2462,7 +3149,7 @@ namespace Game.Achievements } return false; } - case CriteriaAdditionalCondition.SelectedAzeriteEssenceRankGreater: // 267 + case ModifierTreeType.PlayerHasAzeriteEssenceInSlotAtRankGreaterThan: // 267 { Item heartOfAzeroth = referencePlayer.GetItemByEntry(PlayerConst.ItemIdHeartOfAzeroth, ItemSearchLocation.Everywhere); if (heartOfAzeroth != null) @@ -2481,7 +3168,7 @@ namespace Game.Achievements } return false; } - case CriteriaAdditionalCondition.SourceLevelInRangeCt: // 268 + case ModifierTreeType.PlayerLevelWithinContentTuning: // 268 { uint level = referencePlayer.GetLevel(); var levels = Global.DB2Mgr.GetContentTuningData(reqValue, 0); @@ -2493,7 +3180,7 @@ namespace Game.Achievements } return false; } - case CriteriaAdditionalCondition.TargetLevelInRangeCt: // 269 + case ModifierTreeType.TargetLevelWithinContentTuning: // 269 { if (!unit) return false; @@ -2508,7 +3195,16 @@ namespace Game.Achievements } return false; } - case CriteriaAdditionalCondition.SourceLevelGreaterCt: // 272 + case ModifierTreeType.PlayerIsScenarioInitiator: // 270 NYI + return false; + case ModifierTreeType.PlayerHasCompletedQuestOrIsOnQuest: // 271 + { + QuestStatus status = referencePlayer.GetQuestStatus(reqValue); + if (status == QuestStatus.None || status == QuestStatus.Failed) + return false; + break; + } + case ModifierTreeType.PlayerLevelWithinOrAboveContentTuning: // 272 { uint level = referencePlayer.GetLevel(); var levels = Global.DB2Mgr.GetContentTuningData(reqValue, 0); @@ -2516,7 +3212,7 @@ namespace Game.Achievements return secondaryAsset != 0 ? level >= levels.Value.MinLevelWithDelta : level >= levels.Value.MinLevel; return false; } - case CriteriaAdditionalCondition.TargetLevelGreaterCt: // 273 + case ModifierTreeType.TargetLevelWithinOrAboveContentTuning: // 273 { if (!unit) return false; @@ -2527,22 +3223,105 @@ namespace Game.Achievements return secondaryAsset != 0 ? level >= levels.Value.MinLevelWithDelta : level >= levels.Value.MinLevel; return false; } - case CriteriaAdditionalCondition.MapOrCosmeticMap: // 280 + case ModifierTreeType.PlayerLevelWithinOrAboveLevelRange: // 274 NYI + case ModifierTreeType.TargetLevelWithinOrAboveLevelRange: // 275 NYI + return false; + case ModifierTreeType.MaxJailersTowerLevelEqualOrGreaterThan: // 276 + if (referencePlayer.m_activePlayerData.JailersTowerLevelMax < reqValue) + return false; + break; + case ModifierTreeType.GroupedWithRaFRecruit: // 277 + { + var group = referencePlayer.GetGroup(); + if (group == null) + return false; + + for (var itr = group.GetFirstMember(); itr != null; itr = itr.Next()) + if (itr.GetSource().GetSession().GetRecruiterId() == referencePlayer.GetSession().GetAccountId()) + return true; + + return false; + } + case ModifierTreeType.GroupedWithRaFRecruiter: // 278 + { + var group = referencePlayer.GetGroup(); + if (group == null) + return false; + + for (var itr = group.GetFirstMember(); itr != null; 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 { MapRecord map = referencePlayer.GetMap().GetEntry(); if (map.Id != reqValue && map.CosmeticParentMapID != reqValue) return false; break; } - case CriteriaAdditionalCondition.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 != reqValue) return false; break; - case CriteriaAdditionalCondition.Soulbind: // 291 + case ModifierTreeType.HasTimeEventPassed: // 289 + { + long eventTimestamp = GameTime.GetGameTime(); + switch (reqValue) + { + case 111: // Battle for Azeroth Season 4 Start + eventTimestamp = 1579618800L; // January 21, 2020 8:00 + break; + case 120: // Patch 9.0.1 + eventTimestamp = 1602601200L; // October 13, 2020 8:00 + break; + case 121: // Shadowlands Season 1 Start + eventTimestamp = 1607439600L; // 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 != reqValue) return false; break; - case CriteriaAdditionalCondition.SourceAreaOrZoneInGroup: // 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 { var areas = Global.DB2Mgr.GetAreasForGroup(reqValue); AreaTableRecord area = CliDB.AreaTableStorage.LookupByKey(referencePlayer.GetAreaId()); @@ -2552,15 +3331,32 @@ namespace Game.Achievements return true; return false; } - case CriteriaAdditionalCondition.SourceInSpecificChromieTime: // 300 + case ModifierTreeType.TargetIsInAreaGroup: // 299 + { + if (!unit) + return false; + + var areas = Global.DB2Mgr.GetAreasForGroup(reqValue); + var area = CliDB.AreaTableStorage.LookupByKey(unit.GetAreaId()); + if (area != null) + foreach (uint areaInGroup in areas) + if (areaInGroup == area.Id || areaInGroup == area.ParentAreaID) + return true; + return false; + } + case ModifierTreeType.PlayerIsInChromieTime: // 300 if (referencePlayer.m_activePlayerData.UiChromieTimeExpansionID != reqValue) return false; break; - case CriteriaAdditionalCondition.SourceInAnyChromieTime: // 301 + case ModifierTreeType.PlayerIsInAnyChromieTime: // 301 if (referencePlayer.m_activePlayerData.UiChromieTimeExpansionID == 0) return false; break; - case CriteriaAdditionalCondition.SourceRuneforgeLegendaryKnown: // 303 + case ModifierTreeType.ItemIsAzeriteArmor: // 302 + if (Global.DB2Mgr.GetAzeriteEmpoweredItem((uint)miscValue1) == null) + return false; + break; + case ModifierTreeType.PlayerHasRuneforgePower: // 303 { int block = (int)reqValue / 32; if (block >= referencePlayer.m_activePlayerData.RuneforgePowers.Size()) @@ -2569,7 +3365,30 @@ namespace Game.Achievements uint bit = reqValue % 32; return (referencePlayer.m_activePlayerData.RuneforgePowers[block] & (1u << (int)bit)) != 0; } - case CriteriaAdditionalCondition.ShapeshiftFormCustomizationDisplay: // 308 + case ModifierTreeType.PlayerInChromieTimeForScaling: // 304 + if ((referencePlayer.m_playerData.CtrOptions._value.ContentTuningConditionMask & 1) == 0) + return false; + break; + case ModifierTreeType.IsRaFRecruit: // 305 + if (referencePlayer.GetSession().GetRecruiterId() == 0) + return false; + break; + case ModifierTreeType.AllPlayersInGroupHaveAchievement: // 306 + { + var group = referencePlayer.GetGroup(); + if (group != null) + { + for (var itr = group.GetFirstMember(); itr != null; 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 formModelData = Global.DB2Mgr.GetShapeshiftFormModelData(referencePlayer.GetRace(), referencePlayer.GetNativeSex(), (ShapeShiftForm)secondaryAsset); if (formModelData == null) @@ -2584,12 +3403,46 @@ namespace Game.Achievements return false; break; } - case CriteriaAdditionalCondition.SourceFlying: // 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 scenario = referencePlayer.GetScenario(); + if (scenario == null) + return false; + + if (scenario.GetStep() != scenario.GetLastStep()) + return false; + break; + } + case ModifierTreeType.PlayerHasWeeklyRewardsAvailable: // 313 + if (referencePlayer.m_activePlayerData.WeeklyRewardsPeriodSinceOrigin == 0) + return false; break; + case ModifierTreeType.TargetCovenant: // 314 + if (!unit || !unit.IsPlayer()) + return false; + if (unit.ToPlayer().m_playerData.CovenantID != 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/Source/Game/BattlePets/BattlePetManager.cs b/Source/Game/BattlePets/BattlePetManager.cs index 8526ce208..2f7dd645c 100644 --- a/Source/Game/BattlePets/BattlePetManager.cs +++ b/Source/Game/BattlePets/BattlePetManager.cs @@ -319,6 +319,15 @@ namespace Game.BattlePets return (byte)_pets.Values.Count(battlePet => battlePet.PacketInfo.Species == species && battlePet.SaveInfo != BattlePetSaveInfo.Removed); } + public uint GetPetUniqueSpeciesCount() + { + HashSet speciesIds = new(); + foreach (var pair in _pets) + speciesIds.Add(pair.Value.PacketInfo.Species); + + return (uint)speciesIds.Count; + } + public void UnlockSlot(byte slot) { if (!_slots[slot].Locked) @@ -460,6 +469,8 @@ namespace Game.BattlePets public ushort GetTrapLevel() { return _trapLevel; } public List GetSlots() { return _slots; } + public bool HasJournalLock() { return true; } + WorldSession _owner; ushort _trapLevel; Dictionary _pets = new(); diff --git a/Source/Game/DataStorage/DB2Manager.cs b/Source/Game/DataStorage/DB2Manager.cs index 99a65e050..dac51bbbe 100644 --- a/Source/Game/DataStorage/DB2Manager.cs +++ b/Source/Game/DataStorage/DB2Manager.cs @@ -1463,6 +1463,17 @@ namespace Game.DataStorage return bonusListIDs; } + public List GetAllItemBonusTreeBonuses(uint itemBonusTreeId) + { + List bonusListIDs = new List(); + VisitItemBonusTree(itemBonusTreeId, true, bonusTreeNode => + { + if (bonusTreeNode.ChildItemBonusListID != 0) + bonusListIDs.Add(bonusTreeNode.ChildItemBonusListID); + }); + return bonusListIDs; + } + void LoadAzeriteEmpoweredItemUnlockMappings(MultiMap azeriteUnlockMappingsBySet, uint itemId) { var itemIdRange = _itemToBonusTree.LookupByKey(itemId); diff --git a/Source/Game/Entities/Item/Item.cs b/Source/Game/Entities/Item/Item.cs index a8a3cc606..8276b6816 100644 --- a/Source/Game/Entities/Item/Item.cs +++ b/Source/Game/Entities/Item/Item.cs @@ -2089,6 +2089,30 @@ namespace Game.Entities } } + public uint GetTotalUnlockedArtifactPowers() + { + uint purchased = GetTotalPurchasedArtifactPowers(); + ulong artifactXp = m_itemData.ArtifactXP; + uint currentArtifactTier = GetModifier(ItemModifier.ArtifactTier); + uint extraUnlocked = 0; + do + { + ulong xpCost = 0; + var cost = CliDB.ArtifactLevelXPGameTable.GetRow(purchased + extraUnlocked + 1); + if (cost != null) + xpCost = (ulong)(currentArtifactTier == PlayerConst.MaxArtifactTier ? cost.XP2 : cost.XP); + + if (artifactXp < xpCost) + break; + + artifactXp -= xpCost; + ++extraUnlocked; + + } while (true); + + return purchased + extraUnlocked; + } + public uint GetTotalPurchasedArtifactPowers() { uint purchasedRanks = 0; diff --git a/Source/Game/Entities/Player/CollectionManager.cs b/Source/Game/Entities/Player/CollectionManager.cs index d3c446a6d..3d7ece188 100644 --- a/Source/Game/Entities/Player/CollectionManager.cs +++ b/Source/Game/Entities/Player/CollectionManager.cs @@ -728,7 +728,7 @@ namespace Game.Entities { int transmogSlot = Item.ItemTransmogrificationSlots[(int)item.inventoryType]; if (transmogSlot >= 0) - _owner.GetPlayer().UpdateCriteria(CriteriaTypes.AppearanceUnlockedBySlot, (ulong)transmogSlot, 1); + _owner.GetPlayer().UpdateCriteria(CriteriaTypes.AppearanceUnlockedBySlot, (ulong)transmogSlot, itemModifiedAppearance.Id); } var sets = Global.DB2Mgr.GetTransmogSetsForItemModifiedAppearance(itemModifiedAppearance.Id); diff --git a/Source/Game/Entities/Player/Player.Achievement.cs b/Source/Game/Entities/Player/Player.Achievement.cs index 0f5c4ec18..843f66631 100644 --- a/Source/Game/Entities/Player/Player.Achievement.cs +++ b/Source/Game/Entities/Player/Player.Achievement.cs @@ -20,6 +20,7 @@ using Game.Achievements; using Game.DataStorage; using Game.Guilds; using Game.Scenarios; +using System.Collections.Generic; namespace Game.Entities { @@ -39,6 +40,12 @@ namespace Game.Entities { return m_achievementSys.GetAchievementPoints(); } + + public ICollection GetCompletedAchievementIds() + { + return m_achievementSys.GetCompletedAchievementIds(); + } + public bool HasAchieved(uint achievementId) { return m_achievementSys.HasAchieved(achievementId); diff --git a/Source/Game/Entities/Player/Player.Items.cs b/Source/Game/Entities/Player/Player.Items.cs index 5e5b879aa..27bac6522 100644 --- a/Source/Game/Entities/Player/Player.Items.cs +++ b/Source/Game/Entities/Player/Player.Items.cs @@ -1511,7 +1511,7 @@ namespace Game.Entities InventoryResult res = InventoryResult.Ok; uint tempcount = 0; - bool result = ForEachStorageItem(ItemSearchLocation.Equipment, pItem => + bool result = ForEachItem(ItemSearchLocation.Equipment, pItem => { if (pItem.GetEntry() == item) { @@ -2615,7 +2615,7 @@ namespace Game.Entities public Item GetItemByGuid(ObjectGuid guid) { Item result = null; - ForEachStorageItem(ItemSearchLocation.Everywhere, item => + ForEachItem(ItemSearchLocation.Everywhere, item => { if (item.GetGUID() == guid) { @@ -2637,7 +2637,7 @@ namespace Game.Entities location |= ItemSearchLocation.Bank; uint count = 0; - ForEachStorageItem(location, pItem => + ForEachItem(location, pItem => { if (pItem != skipItem) { @@ -2684,7 +2684,7 @@ namespace Game.Entities public Item GetItemByEntry(uint entry, ItemSearchLocation where = ItemSearchLocation.Default) { Item result = null; - ForEachStorageItem(where, item => + ForEachItem(where, item => { if (item.GetEntry() == entry) { @@ -2704,7 +2704,7 @@ namespace Game.Entities location |= ItemSearchLocation.Bank; List itemList = new(); - ForEachStorageItem(location, item => + ForEachItem(location, item => { if (item.GetEntry() == entry) itemList.Add(item); @@ -2721,7 +2721,7 @@ namespace Game.Entities location |= ItemSearchLocation.Bank; uint currentCount = 0; - return !ForEachStorageItem(location, pItem => + return !ForEachItem(location, pItem => { if (pItem && pItem.GetEntry() == item && !pItem.IsInTrade()) { @@ -2791,7 +2791,7 @@ namespace Game.Entities public Item GetChildItemByGuid(ObjectGuid guid) { Item result = null; - ForEachStorageItem(ItemSearchLocation.Equipment | ItemSearchLocation.Inventory, item => + ForEachItem(ItemSearchLocation.Equipment | ItemSearchLocation.Inventory, item => { if (item.GetGUID() == guid) { @@ -2807,7 +2807,7 @@ namespace Game.Entities uint GetItemCountWithLimitCategory(uint limitCategory, Item skipItem) { uint count = 0; - ForEachStorageItem(ItemSearchLocation.Everywhere, item => + ForEachItem(ItemSearchLocation.Everywhere, item => { if (item != skipItem) { @@ -3428,23 +3428,16 @@ namespace Game.Entities return false; } - uint GetMaxPersonalArenaRatingRequirement(uint minarenaslot) + public uint GetMaxPersonalArenaRatingRequirement(uint minarenaslot) { // 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]) uint max_personal_rating = 0; for (byte i = (byte)minarenaslot; i < SharedConst.MaxArenaSlot; ++i) { - ArenaTeam at = Global.ArenaTeamMgr.GetArenaTeamById(GetArenaTeamId(i)); - if (at != null) - { - uint p_rating = GetArenaPersonalRating(i); - uint 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; - } + uint p_rating = GetArenaPersonalRating(i); + if (max_personal_rating < p_rating) + max_personal_rating = p_rating; } return max_personal_rating; } @@ -4469,7 +4462,60 @@ namespace Game.Entities { return StoreItem(dest, pItem, update); } + public uint GetFreeInventorySlotCount(ItemSearchLocation location = ItemSearchLocation.Inventory) + { + uint freeSlotCount = 0; + if (location.HasFlag(ItemSearchLocation.Equipment)) + for (byte i = EquipmentSlot.Start; i < EquipmentSlot.End; ++i) + if (GetItemByPos(InventorySlots.Bag0, i) == null) + ++freeSlotCount; + + if (location.HasFlag(ItemSearchLocation.Inventory)) + { + int inventoryEnd = InventorySlots.ItemStart + GetInventorySlotCount(); + for (byte i = InventorySlots.ItemStart; i < inventoryEnd; ++i) + if (GetItemByPos(InventorySlots.Bag0, i) == null) + ++freeSlotCount; + + for (byte i = InventorySlots.BagStart; i < InventorySlots.BagEnd; ++i) + { + Bag bag = GetBagByPos(i); + if (bag != null) + { + for (byte j = 0; j < bag.GetBagSize(); ++j) + if (bag.GetItemByPos(j) == null) + ++freeSlotCount; + } + } + } + + if (location.HasFlag(ItemSearchLocation.Bank)) + { + for (byte i = InventorySlots.BankItemStart; i < InventorySlots.BankItemEnd; ++i) + if (GetItemByPos(InventorySlots.Bag0, i) == null) + ++freeSlotCount; + + for (byte i = InventorySlots.BankBagStart; i < InventorySlots.BankBagEnd; ++i) + { + Bag bag = GetBagByPos(i); + if (bag != null) + { + for (byte j = 0; j < bag.GetBagSize(); ++j) + if (bag.GetItemByPos(j) == null) + ++freeSlotCount; + } + } + } + + if (location.HasFlag(ItemSearchLocation.ReagentBank)) + for (byte i = InventorySlots.ReagentStart; i < InventorySlots.ReagentEnd; ++i) + if (GetItemByPos(InventorySlots.Bag0, i) == null) + ++freeSlotCount; + + return freeSlotCount; + } + //Bags public Bag GetBagByPos(byte bag) { @@ -5242,7 +5288,7 @@ namespace Game.Entities ItemTemplate pProto = Global.ObjectMgr.GetItemTemplate(item); bool includeGems = pProto?.GetGemProperties() != 0; - return !ForEachStorageItem(ItemSearchLocation.Equipment, pItem => + return !ForEachItem(ItemSearchLocation.Equipment, pItem => { if (pItem.GetSlot() != except_slot) { @@ -5261,7 +5307,7 @@ namespace Game.Entities bool HasItemWithLimitCategoryEquipped(uint limitCategory, uint count, byte except_slot) { uint tempcount = 0; - return !ForEachStorageItem(ItemSearchLocation.Equipment, pItem => + return !ForEachItem(ItemSearchLocation.Equipment, pItem => { if (pItem.GetSlot() == except_slot) return true; @@ -5280,7 +5326,7 @@ namespace Game.Entities bool HasGemWithLimitCategoryEquipped(uint limitCategory, uint count, byte except_slot) { uint tempcount = 0; - return !ForEachStorageItem(ItemSearchLocation.Equipment, pItem => + return !ForEachItem(ItemSearchLocation.Equipment, pItem => { if (pItem.GetSlot() == except_slot) return true; @@ -6555,7 +6601,7 @@ namespace Game.Entities // @todo other types of power scaling such as timewalking } - bool ForEachStorageItem(ItemSearchLocation location, Func callback) + public bool ForEachItem(ItemSearchLocation location, Func callback) { if (location.HasAnyFlag(ItemSearchLocation.Equipment)) { @@ -6720,7 +6766,7 @@ namespace Game.Entities (InventoryType inventoryType, uint itemLevel, ObjectGuid guid)[] bestItemLevels = new (InventoryType inventoryType, uint itemLevel, ObjectGuid guid)[EquipmentSlot.End]; float sum = 0; - ForEachStorageItem(ItemSearchLocation.Everywhere, item => + ForEachItem(ItemSearchLocation.Everywhere, item => { ItemTemplate itemTemplate = item.GetTemplate(); if (itemTemplate != null) diff --git a/Source/Game/Entities/Player/Player.cs b/Source/Game/Entities/Player/Player.cs index d78f26935..a9e219a68 100644 --- a/Source/Game/Entities/Player/Player.cs +++ b/Source/Game/Entities/Player/Player.cs @@ -5015,7 +5015,7 @@ namespace Game.Entities return true; } - bool CanEnableWarModeInArea() + public bool CanEnableWarModeInArea() { var area = CliDB.AreaTableStorage.LookupByKey(GetAreaId()); if (area == null || !IsFriendlyArea(area)) @@ -5878,6 +5878,16 @@ namespace Game.Entities return reputationMgr; } + public void SetReputation(uint factionentry, int value) + { + GetReputationMgr().SetReputation(CliDB.FactionStorage.LookupByKey(factionentry), value); + } + + public int GetReputation(uint factionentry) + { + return GetReputationMgr().GetReputation(CliDB.FactionStorage.LookupByKey(factionentry)); + } + #region Sends / Updates void BeforeVisibilityDestroy(WorldObject obj, Player p) { @@ -6423,12 +6433,12 @@ namespace Game.Entities SendMovementSetCollisionHeight(scale * GetCollisionHeight(), UpdateCollisionHeightReason.Scale); } - bool HasRaceChanged() { return m_ExtraFlags.HasFlag(PlayerExtraFlags.HasRaceChanged); } - void SetHasRaceChanged() { m_ExtraFlags |= PlayerExtraFlags.HasRaceChanged; } - bool HasBeenGrantedLevelsFromRaF() { return m_ExtraFlags.HasFlag(PlayerExtraFlags.GrantedLevelsFromRaf); } - void SetBeenGrantedLevelsFromRaF() { m_ExtraFlags |= PlayerExtraFlags.GrantedLevelsFromRaf; } - bool HasLevelBoosted() { return m_ExtraFlags.HasFlag(PlayerExtraFlags.LevelBoosted); } - void SetHasLevelBoosted() { m_ExtraFlags |= PlayerExtraFlags.LevelBoosted; } + public bool HasRaceChanged() { return m_ExtraFlags.HasFlag(PlayerExtraFlags.HasRaceChanged); } + public void SetHasRaceChanged() { m_ExtraFlags |= PlayerExtraFlags.HasRaceChanged; } + public bool HasBeenGrantedLevelsFromRaF() { return m_ExtraFlags.HasFlag(PlayerExtraFlags.GrantedLevelsFromRaf); } + public void SetBeenGrantedLevelsFromRaF() { m_ExtraFlags |= PlayerExtraFlags.GrantedLevelsFromRaf; } + public bool HasLevelBoosted() { return m_ExtraFlags.HasFlag(PlayerExtraFlags.LevelBoosted); } + public void SetHasLevelBoosted() { m_ExtraFlags |= PlayerExtraFlags.LevelBoosted; } public uint GetXP() { return m_activePlayerData.XP; } public uint GetXPForNextLevel() { return m_activePlayerData.NextLevelXP; } diff --git a/Source/Game/Garrisons/Garrisons.cs b/Source/Game/Garrisons/Garrisons.cs index 7b129e141..877ba0c48 100644 --- a/Source/Game/Garrisons/Garrisons.cs +++ b/Source/Game/Garrisons/Garrisons.cs @@ -310,7 +310,7 @@ namespace Game.Garrisons return _plots.Values; } - Plot GetPlot(uint garrPlotInstanceId) + public Plot GetPlot(uint garrPlotInstanceId) { return _plots.LookupByKey(garrPlotInstanceId); } diff --git a/Source/Game/Handlers/CharacterHandler.cs b/Source/Game/Handlers/CharacterHandler.cs index dab3a0444..17099f290 100644 --- a/Source/Game/Handlers/CharacterHandler.cs +++ b/Source/Game/Handlers/CharacterHandler.cs @@ -123,7 +123,7 @@ namespace Game while (result.NextRow()); } - charResult.IsAlliedRacesCreationAllowed = GetAccountExpansion() >= Expansion.BattleForAzeroth; + charResult.IsAlliedRacesCreationAllowed = CanAccessAlliedRaces(); foreach (var requirement in Global.ObjectMgr.GetRaceUnlockRequirements()) { diff --git a/Source/Game/Reputation/ReputationManager.cs b/Source/Game/Reputation/ReputationManager.cs index 6811745e8..2c1e0ad40 100644 --- a/Source/Game/Reputation/ReputationManager.cs +++ b/Source/Game/Reputation/ReputationManager.cs @@ -182,7 +182,7 @@ namespace Game return GetForcedRankIfAny(factionTemplateEntry.Faction); } - int GetParagonLevel(uint paragonFactionId) + public int GetParagonLevel(uint paragonFactionId) { return GetParagonLevel(CliDB.FactionStorage.LookupByKey(paragonFactionId)); } diff --git a/Source/Game/Scenarios/Scenario.cs b/Source/Game/Scenarios/Scenario.cs index bb27396f7..dd6342385 100644 --- a/Source/Game/Scenarios/Scenario.cs +++ b/Source/Game/Scenarios/Scenario.cs @@ -35,8 +35,8 @@ namespace Game.Scenarios //ASSERT(_data); - foreach (var step in _data.Steps) - SetStepState(step.Value, ScenarioStepState.NotStarted); + foreach (var scenarioStep in _data.Steps.Values) + SetStepState(scenarioStep, ScenarioStepState.NotStarted); ScenarioStepRecord firstStep = GetFirstStep(); if (firstStep != null) @@ -80,16 +80,16 @@ namespace Game.Scenarios return; ScenarioStepRecord newStep = null; - foreach (var _step in _data.Steps.Values) + foreach (var scenarioStep in _data.Steps.Values) { - if (_step.IsBonusObjective()) + if (scenarioStep.IsBonusObjective()) continue; - if (GetStepState(_step) == ScenarioStepState.Done) + if (GetStepState(scenarioStep) == ScenarioStepState.Done) continue; - if (newStep == null || _step.OrderIndex < newStep.OrderIndex) - newStep = _step; + if (newStep == null || scenarioStep.OrderIndex < newStep.OrderIndex) + newStep = scenarioStep; } SetStep(newStep); @@ -129,12 +129,12 @@ namespace Game.Scenarios bool IsComplete() { - foreach (var step in _data.Steps.Values) + foreach (var scenarioStep in _data.Steps.Values) { - if (step.IsBonusObjective()) + if (scenarioStep.IsBonusObjective()) continue; - if (GetStepState(step) != ScenarioStepState.Done) + if (GetStepState(scenarioStep) != ScenarioStepState.Done) return false; } @@ -278,6 +278,22 @@ namespace Game.Scenarios return firstStep; } + public ScenarioStepRecord GetLastStep() + { + // Do it like this because we don't know what order they're in inside the container. + ScenarioStepRecord lastStep = null; + foreach (var scenarioStep in _data.Steps.Values) + { + if (scenarioStep.IsBonusObjective()) + continue; + + if (lastStep == null || scenarioStep.OrderIndex > lastStep.OrderIndex) + lastStep = scenarioStep; + } + + return lastStep; + } + public void SendScenarioState(Player player) { ScenarioState scenarioState = new(); @@ -288,16 +304,16 @@ namespace Game.Scenarios List GetBonusObjectivesData() { List bonusObjectivesData = new(); - foreach (var step in _data.Steps.Values) + foreach (var scenarioStep in _data.Steps.Values) { - if (!step.IsBonusObjective()) + if (!scenarioStep.IsBonusObjective()) continue; - if (Global.CriteriaMgr.GetCriteriaTree(step.CriteriaTreeId) != null) + if (Global.CriteriaMgr.GetCriteriaTree(scenarioStep.CriteriaTreeId) != null) { BonusObjectiveData bonusObjectiveData; - bonusObjectiveData.BonusObjectiveID = (int)step.Id; - bonusObjectiveData.ObjectiveComplete = GetStepState(step) == ScenarioStepState.Done; + bonusObjectiveData.BonusObjectiveID = (int)scenarioStep.Id; + bonusObjectiveData.ObjectiveComplete = GetStepState(scenarioStep) == ScenarioStepState.Done; bonusObjectivesData.Add(bonusObjectiveData); } } diff --git a/Source/Game/Server/WorldSession.cs b/Source/Game/Server/WorldSession.cs index c860ecbb5..dccadadbe 100644 --- a/Source/Game/Server/WorldSession.cs +++ b/Source/Game/Server/WorldSession.cs @@ -676,6 +676,11 @@ namespace Game { return _transactionCallbacks.AddCallback(callback); } + + public bool CanAccessAlliedRaces() + { + return GetAccountExpansion() >= Expansion.BattleForAzeroth; + } void InitWarden(BigInteger k) {