diff --git a/src/game/AchievementMgr.cpp b/src/game/AchievementMgr.cpp index 2e708ae06..c1f8cc3b4 100644 --- a/src/game/AchievementMgr.cpp +++ b/src/game/AchievementMgr.cpp @@ -407,21 +407,21 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui { AchievementCriteriaEntry const *achievementCriteria = (*i); - // don't update already completed criteria - if(IsCompletedCriteria(achievementCriteria)) - continue; - - if(achievementCriteria->groupFlag & ACHIEVEMENT_CRITERIA_GROUP_NOT_IN_GROUP && GetPlayer()->GetGroup()) + if (achievementCriteria->groupFlag & ACHIEVEMENT_CRITERIA_GROUP_NOT_IN_GROUP && GetPlayer()->GetGroup()) continue; AchievementEntry const *achievement = sAchievementStore.LookupEntry(achievementCriteria->referredAchievement); - if(!achievement) + if (!achievement) continue; if ((achievement->factionFlag == ACHIEVEMENT_FACTION_FLAG_HORDE && GetPlayer()->GetTeam() != HORDE) || (achievement->factionFlag == ACHIEVEMENT_FACTION_FLAG_ALLIANCE && GetPlayer()->GetTeam() != ALLIANCE)) continue; + // don't update already completed criteria + if (IsCompletedCriteria(achievementCriteria,achievement)) + continue; + switch (type) { // std. case: increment at 1 @@ -955,20 +955,24 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui case ACHIEVEMENT_CRITERIA_TYPE_TOTAL: break; // Not implemented yet :( } - if(IsCompletedCriteria(achievementCriteria)) - CompletedCriteria(achievementCriteria); + if(IsCompletedCriteria(achievementCriteria,achievement)) + CompletedCriteria(achievementCriteria,achievement); + + + if(AchievementEntryList const* achRefList = achievementmgr.GetAchievementByReferencedId(achievement->ID)) + { + for(AchievementEntryList::const_iterator itr = achRefList->begin(); itr != achRefList->end(); ++itr) + if(IsCompletedAchievement(*itr)) + CompletedAchievement(*itr); + } } } static const uint32 achievIdByClass[MAX_CLASSES] = { 0, 459, 465 , 462, 458, 464, 461, 467, 460, 463, 0, 466 }; static const uint32 achievIdByRace[MAX_RACES] = { 0, 1408, 1410, 1407, 1409, 1413, 1411, 1404, 1412, 0, 1405, 1406 }; -bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achievementCriteria) +bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achievementCriteria, AchievementEntry const* achievement) { - AchievementEntry const* achievement = sAchievementStore.LookupEntry(achievementCriteria->referredAchievement); - if(!achievement) - return false; - // counter can never complete if(achievement->flags & ACHIEVEMENT_FLAG_COUNTER) return false; @@ -1083,45 +1087,64 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achieve return false; } -void AchievementMgr::CompletedCriteria(AchievementCriteriaEntry const* criteria) +void AchievementMgr::CompletedCriteria(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement) { - AchievementEntry const* achievement = sAchievementStore.LookupEntry(criteria->referredAchievement); - if(!achievement) - return; // counter can never complete if(achievement->flags & ACHIEVEMENT_FLAG_COUNTER) return; - if(criteria->completionFlag & ACHIEVEMENT_CRITERIA_COMPLETE_FLAG_ALL || GetAchievementCompletionState(achievement)==ACHIEVEMENT_COMPLETED_COMPLETED_NOT_STORED) - { + // already completed and stored + if (m_completedAchievements.find(achievement->ID)!=m_completedAchievements.end()) + return; + + if ((criteria->referredAchievement==achievement->ID && (criteria->completionFlag & ACHIEVEMENT_CRITERIA_COMPLETE_FLAG_ALL)) || + IsCompletedAchievement(achievement)) CompletedAchievement(achievement); - } } // TODO: achievement 705 requires 4 criteria to be fulfilled -AchievementCompletionState AchievementMgr::GetAchievementCompletionState(AchievementEntry const* entry) +bool AchievementMgr::IsCompletedAchievement(AchievementEntry const* entry) { - if(m_completedAchievements.find(entry->ID)!=m_completedAchievements.end()) - return ACHIEVEMENT_COMPLETED_COMPLETED_STORED; + // for achievement with referenced achievement criterias get from referenced and counter from self + uint32 achievmentForTestId = entry->refAchievement ? entry->refAchievement : entry->ID; + uint32 achievmentForTestCount = entry->count; - bool foundOutstanding = false; - for (uint32 entryId = 0; entryIdbegin(); itr != cList->end(); ++itr) { - AchievementCriteriaEntry const* criteria = sAchievementCriteriaStore.LookupEntry(entryId); - if(!criteria || criteria->referredAchievement!= entry->ID) - continue; + AchievementCriteriaEntry const* criteria = *itr; - if(IsCompletedCriteria(criteria) && criteria->completionFlag & ACHIEVEMENT_CRITERIA_COMPLETE_FLAG_ALL) - return ACHIEVEMENT_COMPLETED_COMPLETED_NOT_STORED; + bool completed = IsCompletedCriteria(criteria,entry); - // found an umcompleted criteria, but DONT return false yet - there might be a completed criteria with ACHIEVEMENT_CRITERIA_COMPLETE_FLAG_ALL - if(!IsCompletedCriteria(criteria)) - foundOutstanding = true; + // found an uncompleted criteria, but DONT return false yet - there might be a completed criteria with ACHIEVEMENT_CRITERIA_COMPLETE_FLAG_ALL + if(completed) + ++count; + else + completed_all = false; + + if(achievmentForTestId == entry->ID) // not referenced achievement + { + // completed as single req. criteria + if(completed && criteria->completionFlag & ACHIEVEMENT_CRITERIA_COMPLETE_FLAG_ALL) + return true; + } + + // completed as have req. count of completed criterias + if(achievmentForTestCount > 0 && achievmentForTestCount <= count) + return true; } - if(foundOutstanding) - return ACHIEVEMENT_COMPLETED_NONE; - else - return ACHIEVEMENT_COMPLETED_COMPLETED_NOT_STORED; + + // all criterias completed requirement + if(completed_all && achievmentForTestCount==0) + return true; + + return false; } void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* entry, uint32 changeValue, ProgressType ptype) @@ -1317,7 +1340,7 @@ void AchievementGlobalMgr::LoadAchievementCriteriaList() } barGoLink bar( sAchievementCriteriaStore.GetNumRows() ); - for (uint32 entryId = 0; entryIdrequiredType].push_back(criteria); + m_AchievementCriteriaListByAchievement[criteria->referredAchievement].push_back(criteria); } sLog.outString(); sLog.outString(">> Loaded %lu achievement criteria.",(unsigned long)m_AchievementCriteriasByType->size()); } +void AchievementGlobalMgr::LoadAchievementReferenceList() +{ + if(sAchievementStore.GetNumRows()==0) + { + barGoLink bar(1); + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded 0 achievement references."); + return; + } + + uint32 count = 0; + barGoLink bar( sAchievementStore.GetNumRows() ); + for (uint32 entryId = 0; entryId < sAchievementStore.GetNumRows(); ++entryId) + { + bar.step(); + + AchievementEntry const* achievement = sAchievementStore.LookupEntry(entryId); + if(!achievement || !achievement->refAchievement) + continue; + + m_AchievementListByReferencedId[achievement->refAchievement].push_back(achievement); + ++count; + } + + sLog.outString(); + sLog.outString(">> Loaded %u achievement references.",count); +} void AchievementGlobalMgr::LoadCompletedAchievements() { diff --git a/src/game/AchievementMgr.h b/src/game/AchievementMgr.h index d355023d6..89ec6ad19 100644 --- a/src/game/AchievementMgr.h +++ b/src/game/AchievementMgr.h @@ -30,7 +30,11 @@ #define CRITERIA_CAST_SPELL_REQ_COUNT 46 #define ACHIEVEMENT_REWARD_COUNT 57 -typedef std::list AchievementCriteriaEntryList; +typedef std::list AchievementCriteriaEntryList; +typedef std::list AchievementEntryList; + +typedef std::map AchievementCriteriaListByAchievement; +typedef std::map AchievementListByReferencedId; struct CriteriaProgress { @@ -80,13 +84,6 @@ class Unit; class Player; class WorldPacket; -enum AchievementCompletionState -{ - ACHIEVEMENT_COMPLETED_NONE, - ACHIEVEMENT_COMPLETED_COMPLETED_NOT_STORED, - ACHIEVEMENT_COMPLETED_COMPLETED_STORED, -}; - class AchievementMgr { public: @@ -108,10 +105,11 @@ class AchievementMgr void SendAchievementEarned(AchievementEntry const* achievement); void SendCriteriaUpdate(uint32 id, CriteriaProgress const* progress); void SetCriteriaProgress(AchievementCriteriaEntry const* entry, uint32 changeValue, ProgressType ptype = PROGRESS_SET); - void CompletedCriteria(AchievementCriteriaEntry const* entry); + void CompletedCriteria(AchievementCriteriaEntry const* entry, AchievementEntry const* achievement); void CompletedAchievement(AchievementEntry const* entry); - bool IsCompletedCriteria(AchievementCriteriaEntry const* entry); - AchievementCompletionState GetAchievementCompletionState(AchievementEntry const* entry); + bool IsCompletedCriteria(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement); + bool IsCompletedAchievement(AchievementEntry const* entry); + void CompleteAchievementsWithRefs(AchievementEntry const* entry); void BuildAllDataPacket(WorldPacket *data); Player* m_player; @@ -123,6 +121,17 @@ class AchievementGlobalMgr { public: AchievementCriteriaEntryList const& GetAchievementCriteriaByType(AchievementCriteriaTypes type); + AchievementCriteriaEntryList const* GetAchievementCriteriaByAchievement(uint32 id) + { + AchievementCriteriaListByAchievement::const_iterator itr = m_AchievementCriteriaListByAchievement.find(id); + return itr != m_AchievementCriteriaListByAchievement.end() ? &itr->second : NULL; + } + + AchievementEntryList const* GetAchievementByReferencedId(uint32 id) const + { + AchievementListByReferencedId::const_iterator itr = m_AchievementListByReferencedId.find(id); + return itr != m_AchievementListByReferencedId.end() ? &itr->second : NULL; + } AchievementReward const* GetAchievementReward(AchievementEntry const* achievement) const { @@ -156,6 +165,7 @@ class AchievementGlobalMgr } void LoadAchievementCriteriaList(); + void LoadAchievementReferenceList(); void LoadCompletedAchievements(); void LoadRewards(); void LoadRewardLocales(); @@ -164,6 +174,10 @@ class AchievementGlobalMgr // store achievement criterias by type to speed up lookup AchievementCriteriaEntryList m_AchievementCriteriasByType[ACHIEVEMENT_CRITERIA_TYPE_TOTAL]; + // store achievement criterias by achievement to speed up lookup + AchievementCriteriaListByAchievement m_AchievementCriteriaListByAchievement; + // store achievements by referenced achievement id to speed up lookup + AchievementListByReferencedId m_AchievementListByReferencedId; typedef std::set AllCompletedAchievements; AllCompletedAchievements m_allCompletedAchievements; diff --git a/src/game/DBCStructure.h b/src/game/DBCStructure.h index c78db7c99..288650f62 100644 --- a/src/game/DBCStructure.h +++ b/src/game/DBCStructure.h @@ -52,8 +52,8 @@ struct AchievementEntry //uint32 icon; // 42 icon (from SpellIcon.dbc) //char *titleReward[16]; // 43-58 //uint32 titleReward_flags; // 59 - //uint32 count; // 60 - need this count Criteria for complete - uint32 refAchievement; // 61 - related achievement? + uint32 count; // 60 - need this count of completed criterias (own or referenced achievement criterias) + uint32 refAchievement; // 61 - referenced achievement (counting of all completed criterias) }; struct AchievementCategoryEntry diff --git a/src/game/DBCfmt.h b/src/game/DBCfmt.h index 8185f83d2..7b3858fda 100644 --- a/src/game/DBCfmt.h +++ b/src/game/DBCfmt.h @@ -19,7 +19,7 @@ #ifndef MANGOS_DBCSFRM_H #define MANGOS_DBCSFRM_H -const char Achievementfmt[]="niixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiixixxxxxxxxxxxxxxxxxxxi"; +const char Achievementfmt[]="niixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiixixxxxxxxxxxxxxxxxxxii"; const char AchievementCriteriafmt[]="niiiiiiiixxxxxxxxxxxxxxxxxiixix"; const char AreaTableEntryfmt[]="iiinixxxxxissssssssssssssssxixxxxxxx"; const char AreaGroupEntryfmt[]="niiiiiii"; diff --git a/src/game/World.cpp b/src/game/World.cpp index 22ae03fc9..00623eca4 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -1265,6 +1265,7 @@ void World::SetInitialWorldSettings() sLog.outString( "Loading Achievements..." ); sLog.outString(); + achievementmgr.LoadAchievementReferenceList(); achievementmgr.LoadAchievementCriteriaList(); achievementmgr.LoadRewards(); achievementmgr.LoadRewardLocales(); diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 9e22415ab..9e908897e 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7606" + #define REVISION_NR "7607" #endif // __REVISION_NR_H__