diff --git a/src/game/Achievements/AchievementMgr.cpp b/src/game/Achievements/AchievementMgr.cpp index c4be78f80..7a249aa71 100644 --- a/src/game/Achievements/AchievementMgr.cpp +++ b/src/game/Achievements/AchievementMgr.cpp @@ -360,10 +360,16 @@ bool AchievementCriteriaData::Meets(uint32 criteria_id, Player const* source, Un case ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT: return sScriptMgr->OnCriteriaCheck(ScriptId, const_cast(source), const_cast(target), criteria_id); case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY: + { if (source->GetMap()->IsRaid()) if (source->GetMap()->Is25ManRaid() != ((difficulty.difficulty & RAID_DIFFICULTY_MASK_25MAN) != 0)) return false; - return source->GetMap()->GetSpawnMode() >= difficulty.difficulty; + + AchievementCriteriaEntry const* criteria = sAchievementCriteriaStore.LookupEntry(criteria_id); + uint8 spawnMode = source->GetMap()->GetSpawnMode(); + // Dungeons completed on heroic mode count towards both in general achievement, but not in statistics. + return sAchievementMgr->IsStatisticCriteria(criteria) ? spawnMode == difficulty.difficulty : spawnMode >= difficulty.difficulty; + } case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT: return source->GetMap()->GetPlayersCountExceptGMs() <= map_players.maxcount; case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM: @@ -2303,6 +2309,32 @@ bool AchievementMgr::CanUpdateCriteria(AchievementCriteriaEntry const* criteria, return true; } +bool AchievementGlobalMgr::IsStatisticCriteria(AchievementCriteriaEntry const* achievementCriteria) const +{ + return isStatisticAchievement(sAchievementStore.LookupEntry(achievementCriteria->referredAchievement)); +} + +bool AchievementGlobalMgr::isStatisticAchievement(AchievementEntry const* achievement) const +{ + if (!achievement) + return false; + + AchievementCategoryEntry const* cat = sAchievementCategoryStore.LookupEntry(achievement->categoryId); + do { + switch(cat->ID) { + case ACHIEVEMENT_CATEGORY_STATISTICS: + return true; + case ACHIEVEMENT_CATEOGRY_GENERAL: + return false; + default: + cat = sAchievementCategoryStore.LookupEntry(cat->parentCategory); + break; + } + } while (cat); + + return false; +} + bool AchievementGlobalMgr::IsRealmCompleted(AchievementEntry const* achievement) const { auto itr = m_allCompletedAchievements.find(achievement->ID); diff --git a/src/game/Achievements/AchievementMgr.h b/src/game/Achievements/AchievementMgr.h index ff5563943..74fe0046e 100644 --- a/src/game/Achievements/AchievementMgr.h +++ b/src/game/Achievements/AchievementMgr.h @@ -56,9 +56,14 @@ enum AchievementCriteriaDataType ACHIEVEMENT_CRITERIA_DATA_TYPE_NTH_BIRTHDAY = 22, // N login on day of N-th Birthday ACHIEVEMENT_CRITERIA_DATA_TYPE_S_KNOWN_TITLE = 23 // title_id known (pvp) title, values from dbc }; - #define MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE 24 // maximum value in AchievementCriteriaDataType enum +enum AchievementCommonCategories +{ + ACHIEVEMENT_CATEOGRY_GENERAL = -1, + ACHIEVEMENT_CATEGORY_STATISTICS = 1 +}; + class Player; class Unit; @@ -295,6 +300,9 @@ class AchievementGlobalMgr ~AchievementGlobalMgr() {} public: + bool IsStatisticCriteria(AchievementCriteriaEntry const* achievementCriteria) const; + bool isStatisticAchievement(AchievementEntry const* achievement) const; + AchievementCriteriaEntryList const* GetAchievementCriteriaByType(AchievementCriteriaTypes type) const { return &m_AchievementCriteriasByType[type]; diff --git a/src/game/DataStores/DBCStores.cpp b/src/game/DataStores/DBCStores.cpp index 2b8b767ce..63a8e9b46 100644 --- a/src/game/DataStores/DBCStores.cpp +++ b/src/game/DataStores/DBCStores.cpp @@ -45,6 +45,7 @@ DBCStorage sAreaPOIStore(AreaPOIEntryfmt); static WMOAreaInfoByTripple sWMOAreaInfoByTripple; DBCStorage sAchievementStore(Achievementfmt); +DBCStorage sAchievementCategoryStore(AchievementCategoryfmt); DBCStorage sAchievementCriteriaStore(AchievementCriteriafmt); DBCStorage sAreaTriggerStore(AreaTriggerEntryfmt); DBCStorage sAuctionHouseStore(AuctionHouseEntryfmt); @@ -256,6 +257,7 @@ void LoadDBCStores(const std::string& dataPath) LoadDBC(availableDbcLocales, bad_dbc_files, sAreaTableStore, dbcPath, "AreaTable.dbc"); LoadDBC(availableDbcLocales, bad_dbc_files, sAchievementStore, dbcPath, "Achievement.dbc", &CustomAchievementfmt, &CustomAchievementIndex); + LoadDBC(availableDbcLocales, bad_dbc_files, sAchievementCategoryStore, dbcPath, "Achievement_Category.dbc"); LoadDBC(availableDbcLocales, bad_dbc_files, sAchievementCriteriaStore, dbcPath, "Achievement_Criteria.dbc"); LoadDBC(availableDbcLocales, bad_dbc_files, sAreaTriggerStore, dbcPath, "AreaTrigger.dbc"); LoadDBC(availableDbcLocales, bad_dbc_files, sAreaGroupStore, dbcPath, "AreaGroup.dbc"); diff --git a/src/game/DataStores/DBCStores.h b/src/game/DataStores/DBCStores.h index d82473b81..a8ca942fd 100644 --- a/src/game/DataStores/DBCStores.h +++ b/src/game/DataStores/DBCStores.h @@ -53,6 +53,7 @@ uint32 GetDefaultMapLight(uint32 mapId); extern DBCStorage sAchievementStore; extern DBCStorage sAchievementCriteriaStore; +extern DBCStorage sAchievementCategoryStore; extern DBCStorage sAreaTableStore; extern DBCStorage sAreaGroupStore; extern DBCStorage sAreaPOIStore; diff --git a/src/game/DataStores/DBCStructure.h b/src/game/DataStores/DBCStructure.h index 3b7ecee54..ed2eb5ae3 100644 --- a/src/game/DataStores/DBCStructure.h +++ b/src/game/DataStores/DBCStructure.h @@ -46,7 +46,7 @@ struct AchievementEntry struct AchievementCategoryEntry { uint32 ID; // 0 - uint32 parentCategory; // 1 -1 for main category + int32 parentCategory; // 1 -1 for main category //char *name[16]; // 2-17 //uint32 name_flags; // 18 //uint32 sortOrder; // 19 diff --git a/src/game/DataStores/DBCfmt.h b/src/game/DataStores/DBCfmt.h index 42cb08c62..bef062b8a 100644 --- a/src/game/DataStores/DBCfmt.h +++ b/src/game/DataStores/DBCfmt.h @@ -10,6 +10,7 @@ char const Achievementfmt[] = "niixssssssssssssssssxxxxxxxxxxxxxxxxxxiixixxxxxxxxxxxxxxxxxxii"; const std::string CustomAchievementfmt="pppaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaapapaaaaaaaaaaaaaaaaaapp"; const std::string CustomAchievementIndex = "ID"; +char const AchievementCategoryfmt[] = "nixxxxxxxxxxxxxxxxxx"; char const AchievementCriteriafmt[] = "niiiiiiiixxxxxxxxxxxxxxxxxiiiix"; char const AreaTableEntryfmt[] = "niiiixxxxxissssssssssssssssxiiiiixxx"; char const AreaGroupEntryfmt[] = "niiiiiii";