[7607] Improvements in support some generic achievement classes

* Implement support achievements with refAchievement field != 0, that have criterias stored in achievement refAchievement.
* Implement support achievement complete req. with specific count of completed critirias.
* Avoid full achievement list scan at search achievement associated with criteria.
This commit is contained in:
VladimirMangos 2009-04-03 00:03:45 +04:00
parent 6c6703f363
commit 0c2f74bb02
6 changed files with 121 additions and 53 deletions

View file

@ -407,21 +407,21 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
{ {
AchievementCriteriaEntry const *achievementCriteria = (*i); AchievementCriteriaEntry const *achievementCriteria = (*i);
// don't update already completed criteria if (achievementCriteria->groupFlag & ACHIEVEMENT_CRITERIA_GROUP_NOT_IN_GROUP && GetPlayer()->GetGroup())
if(IsCompletedCriteria(achievementCriteria))
continue;
if(achievementCriteria->groupFlag & ACHIEVEMENT_CRITERIA_GROUP_NOT_IN_GROUP && GetPlayer()->GetGroup())
continue; continue;
AchievementEntry const *achievement = sAchievementStore.LookupEntry(achievementCriteria->referredAchievement); AchievementEntry const *achievement = sAchievementStore.LookupEntry(achievementCriteria->referredAchievement);
if(!achievement) if (!achievement)
continue; continue;
if ((achievement->factionFlag == ACHIEVEMENT_FACTION_FLAG_HORDE && GetPlayer()->GetTeam() != HORDE) || if ((achievement->factionFlag == ACHIEVEMENT_FACTION_FLAG_HORDE && GetPlayer()->GetTeam() != HORDE) ||
(achievement->factionFlag == ACHIEVEMENT_FACTION_FLAG_ALLIANCE && GetPlayer()->GetTeam() != ALLIANCE)) (achievement->factionFlag == ACHIEVEMENT_FACTION_FLAG_ALLIANCE && GetPlayer()->GetTeam() != ALLIANCE))
continue; continue;
// don't update already completed criteria
if (IsCompletedCriteria(achievementCriteria,achievement))
continue;
switch (type) switch (type)
{ {
// std. case: increment at 1 // std. case: increment at 1
@ -955,20 +955,24 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
case ACHIEVEMENT_CRITERIA_TYPE_TOTAL: case ACHIEVEMENT_CRITERIA_TYPE_TOTAL:
break; // Not implemented yet :( break; // Not implemented yet :(
} }
if(IsCompletedCriteria(achievementCriteria)) if(IsCompletedCriteria(achievementCriteria,achievement))
CompletedCriteria(achievementCriteria); 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 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 }; 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 // counter can never complete
if(achievement->flags & ACHIEVEMENT_FLAG_COUNTER) if(achievement->flags & ACHIEVEMENT_FLAG_COUNTER)
return false; return false;
@ -1083,45 +1087,64 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achieve
return false; 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 // counter can never complete
if(achievement->flags & ACHIEVEMENT_FLAG_COUNTER) if(achievement->flags & ACHIEVEMENT_FLAG_COUNTER)
return; 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); CompletedAchievement(achievement);
}
} }
// TODO: achievement 705 requires 4 criteria to be fulfilled // 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()) // for achievement with referenced achievement criterias get from referenced and counter from self
return ACHIEVEMENT_COMPLETED_COMPLETED_STORED; uint32 achievmentForTestId = entry->refAchievement ? entry->refAchievement : entry->ID;
uint32 achievmentForTestCount = entry->count;
bool foundOutstanding = false; AchievementCriteriaEntryList const* cList = achievementmgr.GetAchievementCriteriaByAchievement(achievmentForTestId);
for (uint32 entryId = 0; entryId<sAchievementCriteriaStore.GetNumRows(); entryId++) if(!cList)
return false;
uint32 count = 0;
bool completed_all = true;
for(AchievementCriteriaEntryList::const_iterator itr = cList->begin(); itr != cList->end(); ++itr)
{ {
AchievementCriteriaEntry const* criteria = sAchievementCriteriaStore.LookupEntry(entryId); AchievementCriteriaEntry const* criteria = *itr;
if(!criteria || criteria->referredAchievement!= entry->ID)
continue;
if(IsCompletedCriteria(criteria) && criteria->completionFlag & ACHIEVEMENT_CRITERIA_COMPLETE_FLAG_ALL) bool completed = IsCompletedCriteria(criteria,entry);
return ACHIEVEMENT_COMPLETED_COMPLETED_NOT_STORED;
// found an umcompleted criteria, but DONT return false yet - there might be a completed criteria with ACHIEVEMENT_CRITERIA_COMPLETE_FLAG_ALL // found an uncompleted criteria, but DONT return false yet - there might be a completed criteria with ACHIEVEMENT_CRITERIA_COMPLETE_FLAG_ALL
if(!IsCompletedCriteria(criteria)) if(completed)
foundOutstanding = true; ++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; // all criterias completed requirement
else if(completed_all && achievmentForTestCount==0)
return ACHIEVEMENT_COMPLETED_COMPLETED_NOT_STORED; return true;
return false;
} }
void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* entry, uint32 changeValue, ProgressType ptype) void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* entry, uint32 changeValue, ProgressType ptype)
@ -1317,7 +1340,7 @@ void AchievementGlobalMgr::LoadAchievementCriteriaList()
} }
barGoLink bar( sAchievementCriteriaStore.GetNumRows() ); barGoLink bar( sAchievementCriteriaStore.GetNumRows() );
for (uint32 entryId = 0; entryId<sAchievementCriteriaStore.GetNumRows(); entryId++) for (uint32 entryId = 0; entryId < sAchievementCriteriaStore.GetNumRows(); ++entryId)
{ {
bar.step(); bar.step();
@ -1326,12 +1349,42 @@ void AchievementGlobalMgr::LoadAchievementCriteriaList()
continue; continue;
m_AchievementCriteriasByType[criteria->requiredType].push_back(criteria); m_AchievementCriteriasByType[criteria->requiredType].push_back(criteria);
m_AchievementCriteriaListByAchievement[criteria->referredAchievement].push_back(criteria);
} }
sLog.outString(); sLog.outString();
sLog.outString(">> Loaded %lu achievement criteria.",(unsigned long)m_AchievementCriteriasByType->size()); 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() void AchievementGlobalMgr::LoadCompletedAchievements()
{ {

View file

@ -30,7 +30,11 @@
#define CRITERIA_CAST_SPELL_REQ_COUNT 46 #define CRITERIA_CAST_SPELL_REQ_COUNT 46
#define ACHIEVEMENT_REWARD_COUNT 57 #define ACHIEVEMENT_REWARD_COUNT 57
typedef std::list<const AchievementCriteriaEntry*> AchievementCriteriaEntryList; typedef std::list<AchievementCriteriaEntry const*> AchievementCriteriaEntryList;
typedef std::list<AchievementEntry const*> AchievementEntryList;
typedef std::map<uint32,AchievementCriteriaEntryList> AchievementCriteriaListByAchievement;
typedef std::map<uint32,AchievementEntryList> AchievementListByReferencedId;
struct CriteriaProgress struct CriteriaProgress
{ {
@ -80,13 +84,6 @@ class Unit;
class Player; class Player;
class WorldPacket; class WorldPacket;
enum AchievementCompletionState
{
ACHIEVEMENT_COMPLETED_NONE,
ACHIEVEMENT_COMPLETED_COMPLETED_NOT_STORED,
ACHIEVEMENT_COMPLETED_COMPLETED_STORED,
};
class AchievementMgr class AchievementMgr
{ {
public: public:
@ -108,10 +105,11 @@ class AchievementMgr
void SendAchievementEarned(AchievementEntry const* achievement); void SendAchievementEarned(AchievementEntry const* achievement);
void SendCriteriaUpdate(uint32 id, CriteriaProgress const* progress); void SendCriteriaUpdate(uint32 id, CriteriaProgress const* progress);
void SetCriteriaProgress(AchievementCriteriaEntry const* entry, uint32 changeValue, ProgressType ptype = PROGRESS_SET); 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); void CompletedAchievement(AchievementEntry const* entry);
bool IsCompletedCriteria(AchievementCriteriaEntry const* entry); bool IsCompletedCriteria(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement);
AchievementCompletionState GetAchievementCompletionState(AchievementEntry const* entry); bool IsCompletedAchievement(AchievementEntry const* entry);
void CompleteAchievementsWithRefs(AchievementEntry const* entry);
void BuildAllDataPacket(WorldPacket *data); void BuildAllDataPacket(WorldPacket *data);
Player* m_player; Player* m_player;
@ -123,6 +121,17 @@ class AchievementGlobalMgr
{ {
public: public:
AchievementCriteriaEntryList const& GetAchievementCriteriaByType(AchievementCriteriaTypes type); 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 AchievementReward const* GetAchievementReward(AchievementEntry const* achievement) const
{ {
@ -156,6 +165,7 @@ class AchievementGlobalMgr
} }
void LoadAchievementCriteriaList(); void LoadAchievementCriteriaList();
void LoadAchievementReferenceList();
void LoadCompletedAchievements(); void LoadCompletedAchievements();
void LoadRewards(); void LoadRewards();
void LoadRewardLocales(); void LoadRewardLocales();
@ -164,6 +174,10 @@ class AchievementGlobalMgr
// store achievement criterias by type to speed up lookup // store achievement criterias by type to speed up lookup
AchievementCriteriaEntryList m_AchievementCriteriasByType[ACHIEVEMENT_CRITERIA_TYPE_TOTAL]; 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<uint32> AllCompletedAchievements; typedef std::set<uint32> AllCompletedAchievements;
AllCompletedAchievements m_allCompletedAchievements; AllCompletedAchievements m_allCompletedAchievements;

View file

@ -52,8 +52,8 @@ struct AchievementEntry
//uint32 icon; // 42 icon (from SpellIcon.dbc) //uint32 icon; // 42 icon (from SpellIcon.dbc)
//char *titleReward[16]; // 43-58 //char *titleReward[16]; // 43-58
//uint32 titleReward_flags; // 59 //uint32 titleReward_flags; // 59
//uint32 count; // 60 - need this count Criteria for complete uint32 count; // 60 - need this count of completed criterias (own or referenced achievement criterias)
uint32 refAchievement; // 61 - related achievement? uint32 refAchievement; // 61 - referenced achievement (counting of all completed criterias)
}; };
struct AchievementCategoryEntry struct AchievementCategoryEntry

View file

@ -19,7 +19,7 @@
#ifndef MANGOS_DBCSFRM_H #ifndef MANGOS_DBCSFRM_H
#define MANGOS_DBCSFRM_H #define MANGOS_DBCSFRM_H
const char Achievementfmt[]="niixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiixixxxxxxxxxxxxxxxxxxxi"; const char Achievementfmt[]="niixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiixixxxxxxxxxxxxxxxxxxii";
const char AchievementCriteriafmt[]="niiiiiiiixxxxxxxxxxxxxxxxxiixix"; const char AchievementCriteriafmt[]="niiiiiiiixxxxxxxxxxxxxxxxxiixix";
const char AreaTableEntryfmt[]="iiinixxxxxissssssssssssssssxixxxxxxx"; const char AreaTableEntryfmt[]="iiinixxxxxissssssssssssssssxixxxxxxx";
const char AreaGroupEntryfmt[]="niiiiiii"; const char AreaGroupEntryfmt[]="niiiiiii";

View file

@ -1265,6 +1265,7 @@ void World::SetInitialWorldSettings()
sLog.outString( "Loading Achievements..." ); sLog.outString( "Loading Achievements..." );
sLog.outString(); sLog.outString();
achievementmgr.LoadAchievementReferenceList();
achievementmgr.LoadAchievementCriteriaList(); achievementmgr.LoadAchievementCriteriaList();
achievementmgr.LoadRewards(); achievementmgr.LoadRewards();
achievementmgr.LoadRewardLocales(); achievementmgr.LoadRewardLocales();

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__ #ifndef __REVISION_NR_H__
#define __REVISION_NR_H__ #define __REVISION_NR_H__
#define REVISION_NR "7606" #define REVISION_NR "7607"
#endif // __REVISION_NR_H__ #endif // __REVISION_NR_H__