aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Achievements/AchievementMgr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/game/Achievements/AchievementMgr.cpp')
-rw-r--r--src/server/game/Achievements/AchievementMgr.cpp1329
1 files changed, 688 insertions, 641 deletions
diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp
index fcafd9c6d01..c392f9d445a 100644
--- a/src/server/game/Achievements/AchievementMgr.cpp
+++ b/src/server/game/Achievements/AchievementMgr.cpp
@@ -17,6 +17,7 @@
*/
#include "AchievementMgr.h"
+#include "AchievementPackets.h"
#include "ArenaTeam.h"
#include "ArenaTeamMgr.h"
#include "Battleground.h"
@@ -43,7 +44,7 @@
#include "World.h"
#include "WorldPacket.h"
-bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
+bool AchievementCriteriaData::IsValid(AchievementCriteria const* criteria)
{
if (dataType >= MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE)
{
@@ -51,7 +52,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
return false;
}
- switch (criteria->type)
+ switch (criteria->Entry->Type)
{
case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE:
case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE:
@@ -81,7 +82,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
default:
if (dataType != ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT)
{
- TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` has data for non-supported criteria type (Entry: %u Type: %u), ignored.", criteria->ID, criteria->type);
+ TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` has data for non-supported criteria type (Entry: %u Type: %u), ignored.", criteria->ID, criteria->Entry->Type);
return false;
}
break;
@@ -96,7 +97,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
if (!creature.id || !sObjectMgr->GetCreatureTemplate(creature.id))
{
TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_CREATURE (%u) has non-existing creature id in value1 (%u), ignored.",
- criteria->ID, criteria->type, dataType, creature.id);
+ criteria->ID, criteria->Entry->Type, dataType, creature.id);
return false;
}
return true;
@@ -104,19 +105,19 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
if (!classRace.class_id && !classRace.race_id)
{
TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE (%u) must not have 0 in either value field, ignored.",
- criteria->ID, criteria->type, dataType);
+ criteria->ID, criteria->Entry->Type, dataType);
return false;
}
if (classRace.class_id && ((1 << (classRace.class_id-1)) & CLASSMASK_ALL_PLAYABLE) == 0)
{
TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE (%u) has non-existing class in value1 (%u), ignored.",
- criteria->ID, criteria->type, dataType, classRace.class_id);
+ criteria->ID, criteria->Entry->Type, dataType, classRace.class_id);
return false;
}
if (classRace.race_id && ((1 << (classRace.race_id-1)) & RACEMASK_ALL_PLAYABLE) == 0)
{
TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE (%u) has non-existing race in value2 (%u), ignored.",
- criteria->ID, criteria->type, dataType, classRace.race_id);
+ criteria->ID, criteria->Entry->Type, dataType, classRace.race_id);
return false;
}
return true;
@@ -124,7 +125,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
if (health.percent < 1 || health.percent > 100)
{
TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_LESS_HEALTH (%u) has wrong percent value in value1 (%u), ignored.",
- criteria->ID, criteria->type, dataType, health.percent);
+ criteria->ID, criteria->Entry->Type, dataType, health.percent);
return false;
}
return true;
@@ -135,20 +136,20 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
if (!spellEntry)
{
TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) has wrong spell id in value1 (%u), ignored.",
- criteria->ID, criteria->type, (dataType == ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA?"ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA":"ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"), dataType, aura.spell_id);
+ criteria->ID, criteria->Entry->Type, (dataType == ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA ? "ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA" : "ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"), dataType, aura.spell_id);
return false;
}
SpellEffectInfo const* effect = spellEntry->GetEffect(DIFFICULTY_NONE, aura.effect_idx);
if (!effect)
{
TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) has wrong spell effect index in value2 (%u), ignored.",
- criteria->ID, criteria->type, (dataType == ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA?"ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA":"ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"), dataType, aura.effect_idx);
+ criteria->ID, criteria->Entry->Type, (dataType == ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA ? "ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA" : "ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"), dataType, aura.effect_idx);
return false;
}
if (!effect->ApplyAuraName)
{
TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) has non-aura spell effect (ID: %u Effect: %u), ignores.",
- criteria->ID, criteria->type, (dataType == ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA?"ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA":"ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"), dataType, aura.spell_id, aura.effect_idx);
+ criteria->ID, criteria->Entry->Type, (dataType == ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA ? "ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA" : "ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"), dataType, aura.spell_id, aura.effect_idx);
return false;
}
return true;
@@ -157,7 +158,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
if (value.compType >= COMP_TYPE_MAX)
{
TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_VALUE (%u) has wrong ComparisionType in value2 (%u), ignored.",
- criteria->ID, criteria->type, dataType, value.compType);
+ criteria->ID, criteria->Entry->Type, dataType, value.compType);
return false;
}
return true;
@@ -165,7 +166,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
if (level.minlevel > STRONG_MAX_LEVEL)
{
TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_LEVEL (%u) has wrong minlevel in value1 (%u), ignored.",
- criteria->ID, criteria->type, dataType, level.minlevel);
+ criteria->ID, criteria->Entry->Type, dataType, level.minlevel);
return false;
}
return true;
@@ -173,7 +174,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
if (gender.gender > GENDER_NONE)
{
TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_GENDER (%u) has wrong gender in value1 (%u), ignored.",
- criteria->ID, criteria->type, dataType, gender.gender);
+ criteria->ID, criteria->Entry->Type, dataType, gender.gender);
return false;
}
return true;
@@ -181,7 +182,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
if (!ScriptId)
{
TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT (%u) does not have ScriptName set, ignored.",
- criteria->ID, criteria->type, dataType);
+ criteria->ID, criteria->Entry->Type, dataType);
return false;
}
return true;
@@ -189,7 +190,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
if (map_players.maxcount <= 0)
{
TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT (%u) has wrong max players count in value1 (%u), ignored.",
- criteria->ID, criteria->type, dataType, map_players.maxcount);
+ criteria->ID, criteria->Entry->Type, dataType, map_players.maxcount);
return false;
}
return true;
@@ -197,7 +198,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
if (team.team != ALLIANCE && team.team != HORDE)
{
TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM (%u) has unknown team in value1 (%u), ignored.",
- criteria->ID, criteria->type, dataType, team.team);
+ criteria->ID, criteria->Entry->Type, dataType, team.team);
return false;
}
return true;
@@ -205,7 +206,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
if (drunk.state >= MAX_DRUNKEN)
{
TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_DRUNK (%u) has unknown drunken state in value1 (%u), ignored.",
- criteria->ID, criteria->type, dataType, drunk.state);
+ criteria->ID, criteria->Entry->Type, dataType, drunk.state);
return false;
}
return true;
@@ -213,7 +214,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
if (!sHolidaysStore.LookupEntry(holiday.id))
{
TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_HOLIDAY (%u) has unknown holiday in value1 (%u), ignored.",
- criteria->ID, criteria->type, dataType, holiday.id);
+ criteria->ID, criteria->Entry->Type, dataType, holiday.id);
return false;
}
return true;
@@ -223,7 +224,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
if (game_event.id < 1 || game_event.id >= events.size())
{
TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_GAME_EVENT (%u) has unknown game_event in value1 (%u), ignored.",
- criteria->ID, criteria->type, dataType, game_event.id);
+ criteria->ID, criteria->Entry->Type, dataType, game_event.id);
return false;
}
return true;
@@ -234,7 +235,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
if (equipped_item.item_quality >= MAX_ITEM_QUALITY)
{
TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPED_ITEM (%u) has unknown quality state in value1 (%u), ignored.",
- criteria->ID, criteria->type, dataType, equipped_item.item_quality);
+ criteria->ID, criteria->Entry->Type, dataType, equipped_item.item_quality);
return false;
}
return true;
@@ -242,19 +243,19 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
if (!classRace.class_id && !classRace.race_id)
{
TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE (%u) must not have 0 in either value field, ignored.",
- criteria->ID, criteria->type, dataType);
+ criteria->ID, criteria->Entry->Type, dataType);
return false;
}
if (classRace.class_id && ((1 << (classRace.class_id-1)) & CLASSMASK_ALL_PLAYABLE) == 0)
{
TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE (%u) has non-existing class in value1 (%u), ignored.",
- criteria->ID, criteria->type, dataType, classRace.class_id);
+ criteria->ID, criteria->Entry->Type, dataType, classRace.class_id);
return false;
}
if (classRace.race_id && ((1 << (classRace.race_id-1)) & RACEMASK_ALL_PLAYABLE) == 0)
{
TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE (%u) has non-existing race in value2 (%u), ignored.",
- criteria->ID, criteria->type, dataType, classRace.race_id);
+ criteria->ID, criteria->Entry->Type, dataType, classRace.race_id);
return false;
}
return true;
@@ -262,12 +263,12 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
if (!sCharTitlesStore.LookupEntry(known_title.title_id))
{
TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_KNOWN_TITLE (%u) have unknown title_id in value1 (%u), ignore.",
- criteria->ID, criteria->type, dataType, known_title.title_id);
+ criteria->ID, criteria->Entry->Type, dataType, known_title.title_id);
return false;
}
return true;
default:
- TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) has data for non-supported data type (%u), ignored.", criteria->ID, criteria->type, dataType);
+ TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) has data for non-supported data type (%u), ignored.", criteria->ID, criteria->Entry->Type, dataType);
return false;
}
}
@@ -383,8 +384,8 @@ bool AchievementCriteriaData::Meets(uint32 criteria_id, Player const* source, Un
bool AchievementCriteriaDataSet::Meets(Player const* source, Unit const* target, uint32 miscValue /*= 0*/) const
{
- for (Storage::const_iterator itr = storage.begin(); itr != storage.end(); ++itr)
- if (!itr->Meets(criteria_id, source, target, miscValue))
+ for (AchievementCriteriaData const& data : storage)
+ if (!data.Meets(criteria_id, source, target, miscValue))
return false;
return true;
@@ -397,22 +398,22 @@ template<class T>
AchievementMgr<T>::~AchievementMgr() { }
template<class T>
-void AchievementMgr<T>::SendPacket(WorldPacket* data) const { }
+void AchievementMgr<T>::SendPacket(WorldPacket const* data) const { }
template<>
-void AchievementMgr<Guild>::SendPacket(WorldPacket* data) const
+void AchievementMgr<Guild>::SendPacket(WorldPacket const* data) const
{
GetOwner()->BroadcastPacket(data);
}
template<>
-void AchievementMgr<Player>::SendPacket(WorldPacket* data) const
+void AchievementMgr<Player>::SendPacket(WorldPacket const* data) const
{
GetOwner()->GetSession()->SendPacket(data);
}
template<class T>
-void AchievementMgr<T>::RemoveCriteriaProgress(AchievementCriteriaEntry const* entry)
+void AchievementMgr<T>::RemoveCriteriaProgress(AchievementCriteria const* entry)
{
if (!entry)
return;
@@ -429,7 +430,7 @@ void AchievementMgr<T>::RemoveCriteriaProgress(AchievementCriteriaEntry const* e
}
template<>
-void AchievementMgr<Guild>::RemoveCriteriaProgress(AchievementCriteriaEntry const* entry)
+void AchievementMgr<Guild>::RemoveCriteriaProgress(AchievementCriteria const* entry)
{
if (!entry)
return;
@@ -474,27 +475,28 @@ void AchievementMgr<T>::ResetAchievementCriteria(AchievementCriteriaTypes type,
if (GetOwner()->IsGameMaster())
return;
- AchievementCriteriaEntryList const& achievementCriteriaList = sAchievementMgr->GetAchievementCriteriaByType(type);
- for (AchievementCriteriaEntryList::const_iterator i = achievementCriteriaList.begin(); i != achievementCriteriaList.end(); ++i)
+ AchievementCriteriaList const& achievementCriteriaList = sAchievementMgr->GetAchievementCriteriaByType(type);
+ for (AchievementCriteria const* achievementCriteria : achievementCriteriaList)
{
- AchievementCriteriaEntry const* achievementCriteria = (*i);
-
- AchievementEntry const* achievement = sAchievementMgr->GetAchievement(achievementCriteria->achievement);
- if (!achievement)
- continue;
-
- // don't update already completed criteria if not forced or achievement already complete
- if ((IsCompletedCriteria(achievementCriteria, achievement) && !evenIfCriteriaComplete) || HasAchieved(achievement->ID))
+ if (achievementCriteria->Entry->FailEvent != miscValue1 || (achievementCriteria->Entry->FailAsset && achievementCriteria->Entry->FailAsset != miscValue2))
continue;
- for (uint8 j = 0; j < MAX_CRITERIA_REQUIREMENTS; ++j)
- if (achievementCriteria->additionalRequirements[j].additionalRequirement_type == miscValue1 &&
- (!achievementCriteria->additionalRequirements[j].additionalRequirement_value ||
- achievementCriteria->additionalRequirements[j].additionalRequirement_value == miscValue2))
+ AchievementCriteriaTreeList const* trees = sAchievementMgr->GetAchievementCriteriaTreesByCriteria(achievementCriteria->ID);
+ bool allComplete = true;
+ for (AchievementCriteriaTree const* tree : *trees)
+ {
+ // don't update already completed criteria if not forced or achievement already complete
+ if (!(IsCompletedCriteriaTree(tree) && !evenIfCriteriaComplete) || !HasAchieved(tree->Achievement->ID))
{
- RemoveCriteriaProgress(achievementCriteria);
+ allComplete = false;
break;
}
+ }
+
+ if (allComplete)
+ continue;
+
+ RemoveCriteriaProgress(achievementCriteria);
}
}
@@ -545,7 +547,6 @@ template<class T>
void AchievementMgr<T>::SaveToDB(SQLTransaction& /*trans*/)
{
}
-
template<>
void AchievementMgr<Player>::SaveToDB(SQLTransaction& trans)
{
@@ -571,6 +572,7 @@ void AchievementMgr<Player>::SaveToDB(SQLTransaction& trans)
}
}
+ /*
if (!m_criteriaProgress.empty())
{
for (CriteriaProgressMap::iterator iter = m_criteriaProgress.begin(); iter != m_criteriaProgress.end(); ++iter)
@@ -596,6 +598,7 @@ void AchievementMgr<Player>::SaveToDB(SQLTransaction& trans)
iter->second.changed = false;
}
}
+ */
}
template<>
@@ -626,6 +629,7 @@ void AchievementMgr<Guild>::SaveToDB(SQLTransaction& trans)
guidstr.str("");
}
+ /*
for (CriteriaProgressMap::const_iterator itr = m_criteriaProgress.begin(); itr != m_criteriaProgress.end(); ++itr)
{
if (!itr->second.changed)
@@ -641,11 +645,11 @@ void AchievementMgr<Guild>::SaveToDB(SQLTransaction& trans)
stmt->setUInt16(1, itr->first);
stmt->setUInt64(2, itr->second.counter);
stmt->setUInt32(3, itr->second.date);
- stmt->setUInt64(4, itr->second.CompletedGUID.GetCounter());
+ stmt->setUInt64(4, itr->second.PlayerGUID.GetCounter());
trans->Append(stmt);
}
+ */
}
-
template<class T>
void AchievementMgr<T>::LoadFromDB(PreparedQueryResult achievementResult, PreparedQueryResult criteriaResult)
{
@@ -682,6 +686,7 @@ void AchievementMgr<Player>::LoadFromDB(PreparedQueryResult achievementResult, P
while (achievementResult->NextRow());
}
+ /*
if (criteriaResult)
{
time_t now = time(NULL);
@@ -692,7 +697,7 @@ void AchievementMgr<Player>::LoadFromDB(PreparedQueryResult achievementResult, P
uint64 counter = fields[1].GetUInt64();
time_t date = time_t(fields[2].GetUInt32());
- AchievementCriteriaEntry const* criteria = sAchievementMgr->GetAchievementCriteria(id);
+ AchievementCriteria const* criteria = sAchievementMgr->GetAchievementCriteria(id);
if (!criteria)
{
// we will remove not existed criteria for all characters
@@ -705,7 +710,7 @@ void AchievementMgr<Player>::LoadFromDB(PreparedQueryResult achievementResult, P
continue;
}
- if (criteria->timeLimit && time_t(date + criteria->timeLimit) < now)
+ if (criteria->Entry->StartTimer && time_t(date + criteria->Entry->StartTimer) < now)
continue;
CriteriaProgress& progress = m_criteriaProgress[id];
@@ -715,6 +720,7 @@ void AchievementMgr<Player>::LoadFromDB(PreparedQueryResult achievementResult, P
}
while (criteriaResult->NextRow());
}
+ */
}
template<>
@@ -745,6 +751,7 @@ void AchievementMgr<Guild>::LoadFromDB(PreparedQueryResult achievementResult, Pr
while (achievementResult->NextRow());
}
+ /*
if (criteriaResult)
{
time_t now = time(NULL);
@@ -756,7 +763,7 @@ void AchievementMgr<Guild>::LoadFromDB(PreparedQueryResult achievementResult, Pr
time_t date = time_t(fields[2].GetUInt32());
ObjectGuid::LowType guid = fields[3].GetUInt64();
- AchievementCriteriaEntry const* criteria = sAchievementMgr->GetAchievementCriteria(id);
+ AchievementCriteria const* criteria = sAchievementMgr->GetAchievementCriteria(id);
if (!criteria)
{
// we will remove not existed criteria for all guilds
@@ -768,16 +775,17 @@ void AchievementMgr<Guild>::LoadFromDB(PreparedQueryResult achievementResult, Pr
continue;
}
- if (criteria->timeLimit && time_t(date + criteria->timeLimit) < now)
+ if (criteria->Entry->StartTimer && time_t(date + criteria->Entry->StartTimer) < now)
continue;
CriteriaProgress& progress = m_criteriaProgress[id];
progress.counter = counter;
progress.date = date;
- progress.CompletedGUID = ObjectGuid::Create<HighGuid::Player>(guid);
+ progress.PlayerGUID = ObjectGuid::Create<HighGuid::Player>(guid);
progress.changed = false;
} while (criteriaResult->NextRow());
}
+ */
}
template<class T>
@@ -840,7 +848,7 @@ void AchievementMgr<Guild>::Reset()
}
while (!m_criteriaProgress.empty())
- if (AchievementCriteriaEntry const* criteria = sAchievementMgr->GetAchievementCriteria(m_criteriaProgress.begin()->first))
+ if (AchievementCriteria const* criteria = sAchievementMgr->GetAchievementCriteria(m_criteriaProgress.begin()->first))
RemoveCriteriaProgress(criteria);
_achievementPoints = 0;
@@ -883,12 +891,13 @@ void AchievementMgr<T>::SendAchievementEarned(AchievementEntry const* achievemen
GetOwner()->VisitNearbyWorldObject(sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), _worker);
}
- WorldPacket data(SMSG_ACHIEVEMENT_EARNED, 8+4+8);
- data << GetOwner()->GetPackGUID();
- data << uint32(achievement->ID);
- data.AppendPackedTime(time(NULL));
- data << uint32(0); // does not notify player ingame
- GetOwner()->SendMessageToSetInRange(&data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), true);
+ WorldPackets::Achievement::AchievementEarned achievementEarned;
+ achievementEarned.Sender = GetOwner()->GetGUID();
+ achievementEarned.Earner = GetOwner()->GetGUID();
+ achievementEarned.EarnerNativeRealm = achievementEarned.EarnerVirtualRealm = GetVirtualRealmAddress();
+ achievementEarned.AchievementID = achievement->ID;
+ achievementEarned.Time = time(NULL);
+ GetOwner()->SendMessageToSetInRange(achievementEarned.Write(), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), true);
}
template<>
@@ -921,39 +930,38 @@ void AchievementMgr<Guild>::SendAchievementEarned(AchievementEntry const* achiev
}
template<class T>
-void AchievementMgr<T>::SendCriteriaUpdate(AchievementCriteriaEntry const* /*entry*/, CriteriaProgress const* /*progress*/, uint32 /*timeElapsed*/, bool /*timedCompleted*/) const
+void AchievementMgr<T>::SendCriteriaUpdate(AchievementCriteria const* /*criteria*/, CriteriaProgress const* /*progress*/, uint32 /*timeElapsed*/, bool /*timedCompleted*/) const
{
}
template<>
-void AchievementMgr<Player>::SendCriteriaUpdate(AchievementCriteriaEntry const* entry, CriteriaProgress const* progress, uint32 timeElapsed, bool timedCompleted) const
+void AchievementMgr<Player>::SendCriteriaUpdate(AchievementCriteria const* criteria, CriteriaProgress const* progress, uint32 timeElapsed, bool timedCompleted) const
{
- WorldPacket data(SMSG_CRITERIA_UPDATE, 8 + 4 + 8);
- data << uint32(entry->ID);
+ WorldPackets::Achievement::CriteriaUpdate criteriaUpdate;
- // the counter is packed like a packed Guid
- data.AppendPackedUInt64(progress->counter);
+ criteriaUpdate.CriteriaID = criteria->ID;
+ criteriaUpdate.Quantity = progress->counter;
+ criteriaUpdate.PlayerGUID = GetOwner()->GetGUID();
+ if (criteria->Entry->StartTimer)
+ criteriaUpdate.Flags = timedCompleted ? 1 : 0; // 1 is for keeping the counter at 0 in client
- data << GetOwner()->GetPackGUID();
- if (!entry->timeLimit)
- data << uint32(0);
- else
- data << uint32(timedCompleted ? 1 : 0); // this are some flags, 1 is for keeping the counter at 0 in client
- data.AppendPackedTime(progress->date);
- data << uint32(timeElapsed); // time elapsed in seconds
- data << uint32(0); // unk
- SendPacket(&data);
+ criteriaUpdate.Flags = 0;
+ criteriaUpdate.CurrentTime = progress->date;
+ criteriaUpdate.ElapsedTime = timeElapsed;
+ criteriaUpdate.CreationTime = 0;
+
+ SendPacket(criteriaUpdate.Write());
}
template<>
-void AchievementMgr<Guild>::SendCriteriaUpdate(AchievementCriteriaEntry const* entry, CriteriaProgress const* progress, uint32 /*timeElapsed*/, bool /*timedCompleted*/) const
+void AchievementMgr<Guild>::SendCriteriaUpdate(AchievementCriteria const* entry, CriteriaProgress const* progress, uint32 /*timeElapsed*/, bool /*timedCompleted*/) const
{
/*
//will send response to criteria progress request
WorldPacket data(SMSG_GUILD_CRITERIA_DATA, 3 + 1 + 1 + 8 + 8 + 4 + 4 + 4 + 4 + 4);
ObjectGuid counter(0, progress->counter); // for accessing every byte individually
- ObjectGuid guid = progress->CompletedGUID;
+ ObjectGuid guid = progress->PlayerGUID;
data.WriteBits(1, 21);
data.WriteBit(counter[4]);
@@ -1016,7 +1024,7 @@ void AchievementMgr<Guild>::SendAllTrackedCriterias(Player* receiver, std::set<u
for (std::set<uint32>::iterator itr = trackedCriterias.begin(); itr != trackedCriterias.end(); ++itr)
{
- AchievementCriteriaEntry const* entry = sAchievementMgr->GetAchievementCriteria(*itr);
+ AchievementCriteriaEntry const* entry = sAchievementMgr->GetAchievementCriteriaTree(*itr);
CriteriaProgressMap::const_iterator progress = m_criteriaProgress.find(entry->ID);
if (progress == m_criteriaProgress.end())
@@ -1032,14 +1040,14 @@ void AchievementMgr<Guild>::SendAllTrackedCriterias(Player* receiver, std::set<u
for (std::set<uint32>::iterator itr = trackedCriterias.begin(); itr != trackedCriterias.end(); ++itr)
{
- AchievementCriteriaEntry const* entry = sAchievementMgr->GetAchievementCriteria(*itr);
+ AchievementCriteriaEntry const* entry = sAchievementMgr->GetAchievementCriteriaTree(*itr);
CriteriaProgressMap::const_iterator progress = m_criteriaProgress.find(entry->ID);
if (progress == m_criteriaProgress.end())
continue;
counter.SetRawValue(progress->second.counter);
- guid = progress->second.CompletedGUID;
+ guid = progress->second.PlayerGUID;
criteriaBits.WriteBit(counter[4]);
criteriaBits.WriteBit(counter[1]);
@@ -1102,18 +1110,6 @@ void AchievementMgr<T>::CheckAllAchievementCriteria(Player* referencePlayer)
UpdateAchievementCriteria(AchievementCriteriaTypes(i), 0, 0, 0, NULL, referencePlayer);
}
-static const uint32 achievIdByArenaSlot[MAX_ARENA_SLOT] = {1057, 1107, 1108};
-static const uint32 achievIdForDungeon[][4] =
-{
- // ach_cr_id, is_dungeon, is_raid, is_heroic_dungeon
- { 321, true, true, true },
- { 916, false, true, false },
- { 917, false, true, false },
- { 918, true, false, false },
- { 2219, false, false, true },
- { 0, false, false, false }
-};
-
// Helper function to avoid having to specialize template for a 800 line long function
template <typename T> static bool IsGuild() { return false; }
template<> bool IsGuild<Guild>() { return true; }
@@ -1151,18 +1147,12 @@ void AchievementMgr<T>::UpdateAchievementCriteria(AchievementCriteriaTypes type,
if (IsGuild<T>() && !sWorld->getBoolConfig(CONFIG_GUILD_LEVELING_ENABLED))
return;
- AchievementCriteriaEntryList const& achievementCriteriaList = sAchievementMgr->GetAchievementCriteriaByType(type, IsGuild<T>());
- for (AchievementCriteriaEntryList::const_iterator i = achievementCriteriaList.begin(); i != achievementCriteriaList.end(); ++i)
+ AchievementCriteriaList const& achievementCriteriaList = sAchievementMgr->GetAchievementCriteriaByType(type, IsGuild<T>());
+ for (AchievementCriteria const* achievementCriteria : achievementCriteriaList)
{
- AchievementCriteriaEntry const* achievementCriteria = (*i);
- AchievementEntry const* achievement = sAchievementMgr->GetAchievement(achievementCriteria->achievement);
- if (!achievement)
- {
- TC_LOG_ERROR("achievement", "UpdateAchievementCriteria: Achievement %u not found!", achievementCriteria->achievement);
- continue;
- }
+ AchievementCriteriaTreeList const* trees = sAchievementMgr->GetAchievementCriteriaTreesByCriteria(achievementCriteria->ID);
- if (!CanUpdateCriteria(achievementCriteria, achievement, miscValue1, miscValue2, miscValue3, unit, referencePlayer))
+ if (!CanUpdateCriteria(achievementCriteria, trees, miscValue1, miscValue2, miscValue3, unit, referencePlayer))
continue;
// requirements not found in the dbc
@@ -1253,11 +1243,11 @@ void AchievementMgr<T>::UpdateAchievementCriteria(AchievementCriteriaTypes type,
SetCriteriaProgress(achievementCriteria, referencePlayer->getLevel(), referencePlayer);
break;
case ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL:
- if (uint32 skillvalue = referencePlayer->GetBaseSkillValue(achievementCriteria->reach_skill_level.skillID))
+ if (uint32 skillvalue = referencePlayer->GetBaseSkillValue(achievementCriteria->Entry->Asset.SkillID))
SetCriteriaProgress(achievementCriteria, skillvalue, referencePlayer);
break;
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL:
- if (uint32 maxSkillvalue = referencePlayer->GetPureMaxSkillValue(achievementCriteria->learn_skill_level.skillID))
+ if (uint32 maxSkillvalue = referencePlayer->GetPureMaxSkillValue(achievementCriteria->Entry->Asset.SkillID))
SetCriteriaProgress(achievementCriteria, maxSkillvalue, referencePlayer);
break;
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT:
@@ -1301,7 +1291,7 @@ void AchievementMgr<T>::UpdateAchievementCriteria(AchievementCriteriaTypes type,
for (RewardedQuestSet::const_iterator itr = rewQuests.begin(); itr != rewQuests.end(); ++itr)
{
Quest const* quest = sObjectMgr->GetQuestTemplate(*itr);
- if (quest && quest->GetZoneOrSort() >= 0 && uint32(quest->GetZoneOrSort()) == achievementCriteria->complete_quests_in_zone.zoneID)
+ if (quest && quest->GetZoneOrSort() >= 0 && uint32(quest->GetZoneOrSort()) == achievementCriteria->Entry->Asset.ZoneID)
++counter;
}
SetCriteriaProgress(achievementCriteria, counter, referencePlayer);
@@ -1325,7 +1315,7 @@ void AchievementMgr<T>::UpdateAchievementCriteria(AchievementCriteriaTypes type,
break;
case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION:
{
- int32 reputation = referencePlayer->GetReputationMgr().GetReputation(achievementCriteria->gain_reputation.factionID);
+ int32 reputation = referencePlayer->GetReputationMgr().GetReputation(achievementCriteria->Entry->Asset.FactionID);
if (reputation > 0)
SetCriteriaProgress(achievementCriteria, reputation, referencePlayer);
break;
@@ -1343,7 +1333,7 @@ void AchievementMgr<T>::UpdateAchievementCriteria(AchievementCriteriaTypes type,
SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellIter->first);
for (SkillLineAbilityMap::const_iterator skillIter = bounds.first; skillIter != bounds.second; ++skillIter)
{
- if (skillIter->second->SkillLine == achievementCriteria->learn_skillline_spell.skillLine)
+ if (skillIter->second->SkillLine == achievementCriteria->Entry->Asset.SkillID)
spellCount++;
}
}
@@ -1368,7 +1358,7 @@ void AchievementMgr<T>::UpdateAchievementCriteria(AchievementCriteriaTypes type,
{
SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellIter->first);
for (SkillLineAbilityMap::const_iterator skillIter = bounds.first; skillIter != bounds.second; ++skillIter)
- if (skillIter->second->SkillLine == achievementCriteria->learn_skill_line.skillLine)
+ if (skillIter->second->SkillLine == achievementCriteria->Entry->Asset.SkillID)
spellCount++;
}
SetCriteriaProgress(achievementCriteria, spellCount, referencePlayer);
@@ -1388,7 +1378,7 @@ void AchievementMgr<T>::UpdateAchievementCriteria(AchievementCriteriaTypes type,
break;
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING:
{
- uint32 reqTeamType = achievementCriteria->highest_team_rating.teamtype;
+ uint32 reqTeamType = achievementCriteria->Entry->Asset.TeamType;
if (miscValue1)
{
@@ -1418,7 +1408,7 @@ void AchievementMgr<T>::UpdateAchievementCriteria(AchievementCriteriaTypes type,
}
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_PERSONAL_RATING:
{
- uint32 reqTeamType = achievementCriteria->highest_personal_rating.teamtype;
+ uint32 reqTeamType = achievementCriteria->Entry->Asset.TeamType;
if (miscValue1)
{
@@ -1472,19 +1462,22 @@ void AchievementMgr<T>::UpdateAchievementCriteria(AchievementCriteriaTypes type,
break; // Not implemented yet :(
}
- if (IsCompletedCriteria(achievementCriteria, achievement))
- CompletedCriteriaFor(achievement, referencePlayer);
-
- // check again the completeness for SUMM and REQ COUNT achievements,
- // as they don't depend on the completed criteria but on the sum of the progress of each individual criteria
- if (achievement->Flags & ACHIEVEMENT_FLAG_SUMM)
- if (IsCompletedAchievement(achievement))
- CompletedAchievement(achievement, referencePlayer);
-
- if (AchievementEntryList const* achRefList = sAchievementMgr->GetAchievementByReferencedId(achievement->ID))
- for (AchievementEntryList::const_iterator itr = achRefList->begin(); itr != achRefList->end(); ++itr)
- if (IsCompletedAchievement(*itr))
- CompletedAchievement(*itr, referencePlayer);
+ for (AchievementCriteriaTree const* tree : *trees)
+ {
+ if (IsCompletedCriteriaTree(tree))
+ CompletedCriteriaFor(tree->Achievement, referencePlayer);
+
+ // check again the completeness for SUMM and REQ COUNT achievements,
+ // as they don't depend on the completed criteria but on the sum of the progress of each individual criteria
+ if (tree->Achievement->Flags & ACHIEVEMENT_FLAG_SUMM)
+ if (IsCompletedAchievement(tree->Achievement))
+ CompletedAchievement(tree->Achievement, referencePlayer);
+
+ if (AchievementEntryList const* achRefList = sAchievementMgr->GetAchievementByReferencedId(tree->Achievement->ID))
+ for (AchievementEntry const* refAchievement : *achRefList)
+ if (IsCompletedAchievement(refAchievement))
+ CompletedAchievement(refAchievement, referencePlayer);
+ }
}
}
@@ -1497,8 +1490,9 @@ template<>
uint32 GetInstanceId(Player* player) { return player->GetInstanceId(); }
template<class T>
-bool AchievementMgr<T>::IsCompletedCriteria(AchievementCriteriaEntry const* achievementCriteria, AchievementEntry const* achievement)
+bool AchievementMgr<T>::IsCompletedCriteriaTree(AchievementCriteriaTree const* tree)
{
+ AchievementEntry const* achievement = tree->Achievement;
if (!achievement)
return false;
@@ -1513,116 +1507,109 @@ bool AchievementMgr<T>::IsCompletedCriteria(AchievementCriteriaEntry const* achi
return false;
}
+ uint64 requiredCount = tree->Entry->Amount;
+ uint64 completedCount = 0;
+ uint32 op = tree->Entry->Operator;
+ bool hasAll = true;
+
+ // Check criteria we depend on first
+ for (AchievementCriteriaTree const* node : tree->Children)
+ {
+ if (IsCompletedCriteriaTree(node))
+ ++completedCount;
+ else
+ hasAll = false;
+
+ if (op & ACHIEVEMENT_CRITERIA_TREE_OPERATOR_ANY && completedCount >= requiredCount)
+ {
+ if (!tree->Criteria)
+ return true;
+
+ break;
+ }
+ }
+
+ if (op & ACHIEVEMENT_CRITERIA_TREE_OPERATOR_ANY && completedCount < requiredCount)
+ return false;
+
+ if (op & ACHIEVEMENT_CRITERIA_TREE_OPERATOR_ALL && !hasAll)
+ return false;
+
+ if (!tree->Criteria)
+ return true;
+
+ return IsCompletedCriteria(tree->Criteria, requiredCount);
+}
+
+template<class T>
+bool AchievementMgr<T>::IsCompletedCriteria(AchievementCriteria const* achievementCriteria, uint64 requiredAmount)
+{
CriteriaProgress const* progress = GetCriteriaProgress(achievementCriteria);
if (!progress)
return false;
- switch (AchievementCriteriaTypes(achievementCriteria->type))
+ switch (AchievementCriteriaTypes(achievementCriteria->Entry->Type))
{
case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG:
- return progress->counter >= achievementCriteria->win_bg.winCount;
case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE:
- return progress->counter >= achievementCriteria->kill_creature.creatureCount;
case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL:
case ACHIEVEMENT_CRITERIA_TYPE_REACH_GUILD_LEVEL:
- return progress->counter >= achievementCriteria->reach_level.level;
case ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL:
- return progress->counter >= achievementCriteria->reach_skill_level.skillLevel;
- case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT:
- return progress->counter >= 1;
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT:
- return progress->counter >= achievementCriteria->complete_quest_count.totalQuestCount;
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY:
- return progress->counter >= achievementCriteria->complete_daily_quest_daily.numberOfDays;
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE:
- return progress->counter >= achievementCriteria->complete_quests_in_zone.questCount;
case ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE:
case ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE:
- return progress->counter >= achievementCriteria->healing_done.count;
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST:
- return progress->counter >= achievementCriteria->complete_daily_quest.questCount;
case ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING:
- return progress->counter >= achievementCriteria->fall_without_dying.fallHeight;
- case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST:
- return progress->counter >= 1;
case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET:
case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2:
- return progress->counter >= achievementCriteria->be_spell_target.spellCount;
case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL:
case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2:
- return progress->counter >= achievementCriteria->cast_spell.castCount;
case ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE:
- return progress->counter >= achievementCriteria->bg_objective.completeCount;
case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA:
- return progress->counter >= achievementCriteria->honorable_kill_at_area.killCount;
- case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL:
- return progress->counter >= 1;
case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL:
case ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL:
- return progress->counter >= achievementCriteria->honorable_kill.killCount;
case ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM:
- return progress->counter >= achievementCriteria->own_item.itemCount;
case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA:
- return progress->counter >= achievementCriteria->win_rated_arena.count;
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_PERSONAL_RATING:
- return progress->counter >= achievementCriteria->highest_personal_rating.PersonalRating;
- case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL:
- return progress->counter >= (achievementCriteria->learn_skill_level.skillLevel * 75);
case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM:
- return progress->counter >= achievementCriteria->use_item.itemCount;
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM:
- return progress->counter >= achievementCriteria->loot_item.itemCount;
- case ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA:
- return progress->counter >= 1;
case ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT:
- return progress->counter >= achievementCriteria->buy_bank_slot.numberOfSlots;
case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION:
- return progress->counter >= achievementCriteria->gain_reputation.reputationAmount;
case ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION:
- return progress->counter >= achievementCriteria->gain_exalted_reputation.numberOfExaltedFactions;
case ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP:
- return progress->counter >= achievementCriteria->visit_barber.numberOfVisits;
case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM:
- return progress->counter >= achievementCriteria->equip_epic_item.count;
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT:
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT:
- return progress->counter >= achievementCriteria->roll_greed_on_loot.count;
case ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS:
- return progress->counter >= achievementCriteria->hk_class.count;
case ACHIEVEMENT_CRITERIA_TYPE_HK_RACE:
- return progress->counter >= achievementCriteria->hk_race.count;
case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE:
- return progress->counter >= achievementCriteria->do_emote.count;
case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM:
- return progress->counter >= achievementCriteria->equip_item.count;
case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD:
- return progress->counter >= achievementCriteria->quest_reward_money.goldInCopper;
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY:
- return progress->counter >= achievementCriteria->loot_money.goldInCopper;
case ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT:
- return progress->counter >= achievementCriteria->use_gameobject.useCount;
case ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL:
- return progress->counter >= achievementCriteria->special_pvp_kill.killCount;
case ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT:
- return progress->counter >= achievementCriteria->fish_in_gameobject.lootCount;
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS:
- return progress->counter >= achievementCriteria->learn_skillline_spell.spellCount;
case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL:
- return progress->counter >= achievementCriteria->win_duel.duelCount;
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE:
- return progress->counter >= achievementCriteria->loot_type.lootTypeCount;
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE:
- return progress->counter >= achievementCriteria->learn_skill_line.spellCount;
- case ACHIEVEMENT_CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS:
- return progress->counter >= 9000;
case ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS:
- return progress->counter >= achievementCriteria->use_lfg.dungeonsComplete;
case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS:
- return progress->counter >= achievementCriteria->get_killing_blow.killCount;
case ACHIEVEMENT_CRITERIA_TYPE_CURRENCY:
- return progress->counter >= achievementCriteria->currencyGain.count;
+ return progress->counter >= requiredAmount;
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT:
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST:
+ case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL:
+ case ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA:
+ return progress->counter >= 1;
+ case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL:
+ return progress->counter >= (requiredAmount * 75);
+ case ACHIEVEMENT_CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS:
+ return progress->counter >= 9000;
case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA:
- return achievementCriteria->win_arena.count && progress->counter >= achievementCriteria->win_arena.count;
+ return requiredAmount && progress->counter >= requiredAmount;
case ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN:
return true;
// handle all statistic-only criteria here
@@ -1680,70 +1667,40 @@ void AchievementMgr<T>::CompletedCriteriaFor(AchievementEntry const* achievement
}
template<class T>
+uint64 AchievementMgr<T>::GetTotalCriteriaTreeProgress(AchievementCriteriaTree const* criteriaTree)
+{
+ uint64 progress = 0;
+ if (criteriaTree->Criteria)
+ if (CriteriaProgress const* criteriaProgress = GetCriteriaProgress(criteriaTree->Criteria))
+ progress += criteriaProgress->counter;
+
+ for (AchievementCriteriaTree const* node : criteriaTree->Children)
+ progress += GetTotalCriteriaTreeProgress(node);
+
+ return progress;
+}
+
+template<class T>
bool AchievementMgr<T>::IsCompletedAchievement(AchievementEntry const* entry)
{
// counter can never complete
if (entry->Flags & ACHIEVEMENT_FLAG_COUNTER)
return false;
- // for achievement with referenced achievement criterias get from referenced and counter from self
- uint32 achievementForTestId = entry->SharesCriteria ? entry->SharesCriteria : entry->ID;
- uint32 achievementForTestCount = entry->MinimumCriteria;
-
- AchievementCriteriaEntryList const* cList = sAchievementMgr->GetAchievementCriteriaByAchievement(achievementForTestId);
- if (!cList)
+ AchievementCriteriaTree const* tree = sAchievementMgr->GetAchievementCriteriaTree(entry->CriteriaTree);
+ if (!tree)
return false;
- uint64 count = 0;
// For SUMM achievements, we have to count the progress of each criteria of the achievement.
// Oddly, the target count is NOT contained in the achievement, but in each individual criteria
if (entry->Flags & ACHIEVEMENT_FLAG_SUMM)
- {
- for (AchievementCriteriaEntryList::const_iterator itr = cList->begin(); itr != cList->end(); ++itr)
- {
- AchievementCriteriaEntry const* criteria = *itr;
-
- CriteriaProgress const* progress = GetCriteriaProgress(criteria);
- if (!progress)
- continue;
-
- count += progress->counter;
-
- // for counters, field4 contains the main count requirement
- if (count >= criteria->raw.count)
- return true;
- }
- return false;
- }
-
- // Default case - need complete all or
- bool completed_all = true;
- for (AchievementCriteriaEntryList::const_iterator itr = cList->begin(); itr != cList->end(); ++itr)
- {
- AchievementCriteriaEntry const* criteria = *itr;
-
- bool completed = IsCompletedCriteria(criteria, entry);
-
- // 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;
+ return GetTotalCriteriaTreeProgress(tree) >= tree->Entry->Amount;
- // completed as have req. count of completed criterias
- if (achievementForTestCount > 0 && achievementForTestCount <= count)
- return true;
- }
-
- // all criterias completed requirement
- if (completed_all && achievementForTestCount == 0)
- return true;
-
- return false;
+ return IsCompletedCriteriaTree(tree);
}
template<class T>
-CriteriaProgress* AchievementMgr<T>::GetCriteriaProgress(AchievementCriteriaEntry const* entry)
+CriteriaProgress* AchievementMgr<T>::GetCriteriaProgress(AchievementCriteria const* entry)
{
CriteriaProgressMap::iterator iter = m_criteriaProgress.find(entry->ID);
@@ -1754,25 +1711,44 @@ CriteriaProgress* AchievementMgr<T>::GetCriteriaProgress(AchievementCriteriaEntr
}
template<class T>
-void AchievementMgr<T>::SetCriteriaProgress(AchievementCriteriaEntry const* entry, uint64 changeValue, Player* referencePlayer, ProgressType ptype)
+void AchievementMgr<T>::SetCriteriaProgress(AchievementCriteria const* criteria, uint64 changeValue, Player* referencePlayer, ProgressType ptype)
{
// Don't allow to cheat - doing timed achievements without timer active
- TimedAchievementMap::iterator timedIter = m_timedAchievements.find(entry->ID);
- if (entry->timeLimit && timedIter == m_timedAchievements.end())
- return;
+ AchievementCriteriaTreeList const* trees = nullptr;
+ if (criteria->Entry->StartTimer)
+ {
+ trees = sAchievementMgr->GetAchievementCriteriaTreesByCriteria(criteria->ID);
+ if (!trees)
+ return;
+
+ bool hasTreeForTimed = false;
+ for (AchievementCriteriaTree const* tree : *trees)
+ {
+ auto timedIter = m_timedAchievements.find(tree->ID);
+ if (timedIter != m_timedAchievements.end())
+ {
+ hasTreeForTimed = true;
+ break;
+ }
+
+ }
+
+ if (!hasTreeForTimed)
+ return;
+ }
TC_LOG_DEBUG("achievement", "SetCriteriaProgress(%u, " UI64FMTD ") for (%s)",
- entry->ID, changeValue, GetOwner()->GetGUID().ToString().c_str());
+ criteria->ID, changeValue, GetOwner()->GetGUID().ToString().c_str());
- CriteriaProgress* progress = GetCriteriaProgress(entry);
+ CriteriaProgress* progress = GetCriteriaProgress(criteria);
if (!progress)
{
// not create record for 0 counter but allow it for timed achievements
// we will need to send 0 progress to client to start the timer
- if (changeValue == 0 && !entry->timeLimit)
+ if (changeValue == 0 && !criteria->Entry->StartTimer)
return;
- progress = &m_criteriaProgress[entry->ID];
+ progress = &m_criteriaProgress[criteria->ID];
progress->counter = changeValue;
}
else
@@ -1796,7 +1772,7 @@ void AchievementMgr<T>::SetCriteriaProgress(AchievementCriteriaEntry const* entr
}
// not update (not mark as changed) if counter will have same value
- if (progress->counter == newValue && !entry->timeLimit)
+ if (progress->counter == newValue && !criteria->Entry->StartTimer)
return;
progress->counter = newValue;
@@ -1804,25 +1780,30 @@ void AchievementMgr<T>::SetCriteriaProgress(AchievementCriteriaEntry const* entr
progress->changed = true;
progress->date = time(NULL); // set the date to the latest update.
+ progress->PlayerGUID = referencePlayer->GetGUID();
- AchievementEntry const* achievement = sAchievementMgr->GetAchievement(entry->achievement);
uint32 timeElapsed = 0;
- bool criteriaComplete = IsCompletedCriteria(entry, achievement);
- if (entry->timeLimit)
+ if (criteria->Entry->StartTimer)
{
- // Client expects this in packet
- timeElapsed = entry->timeLimit - (timedIter->second/IN_MILLISECONDS);
+ ASSERT(trees);
- // Remove the timer, we wont need it anymore
- if (criteriaComplete)
- m_timedAchievements.erase(timedIter);
- }
+ for (AchievementCriteriaTree const* tree : *trees)
+ {
+ auto timedIter = m_timedAchievements.find(tree->ID);
+ if (timedIter != m_timedAchievements.end())
+ {
+ // Client expects this in packet
+ timeElapsed = criteria->Entry->StartTimer - (timedIter->second / IN_MILLISECONDS);
- if (criteriaComplete && achievement->Flags & ACHIEVEMENT_FLAG_SHOW_CRITERIA_MEMBERS && !progress->CompletedGUID)
- progress->CompletedGUID = referencePlayer->GetGUID();
+ // Remove the timer, we wont need it anymore
+ if (IsCompletedCriteriaTree(tree))
+ m_timedAchievements.erase(timedIter);
+ }
+ }
+ }
- SendCriteriaUpdate(entry, progress, timeElapsed, criteriaComplete);
+ SendCriteriaUpdate(criteria, progress, timeElapsed, true);
}
template<class T>
@@ -1835,8 +1816,10 @@ void AchievementMgr<T>::UpdateTimedAchievements(uint32 timeDiff)
// Time is up, remove timer and reset progress
if (itr->second <= timeDiff)
{
- AchievementCriteriaEntry const* entry = sAchievementMgr->GetAchievementCriteria(itr->first);
- RemoveCriteriaProgress(entry);
+ AchievementCriteriaTree const* criteriaTree = sAchievementMgr->GetAchievementCriteriaTree(itr->first);
+ if (criteriaTree->Criteria)
+ RemoveCriteriaProgress(criteriaTree->Criteria);
+
m_timedAchievements.erase(itr++);
}
else
@@ -1856,46 +1839,51 @@ void AchievementMgr<T>::StartTimedAchievement(AchievementCriteriaTimedTypes /*ty
template<>
void AchievementMgr<Player>::StartTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry, uint32 timeLost /* = 0 */)
{
- AchievementCriteriaEntryList const& achievementCriteriaList = sAchievementMgr->GetTimedAchievementCriteriaByType(type);
- for (AchievementCriteriaEntryList::const_iterator i = achievementCriteriaList.begin(); i != achievementCriteriaList.end(); ++i)
+ AchievementCriteriaList const& achievementCriteriaList = sAchievementMgr->GetTimedAchievementCriteriaByType(type);
+ for (AchievementCriteria const* criteria : achievementCriteriaList)
{
- if ((*i)->timedCriteriaMiscId != entry)
+ if (criteria->Entry->StartAsset != entry)
continue;
- AchievementEntry const* achievement = sAchievementMgr->GetAchievement((*i)->achievement);
- if (m_timedAchievements.find((*i)->ID) == m_timedAchievements.end() && !IsCompletedCriteria(*i, achievement))
+ AchievementCriteriaTreeList const* trees = sAchievementMgr->GetAchievementCriteriaTreesByCriteria(criteria->ID);
+ bool canStart = false;
+ for (AchievementCriteriaTree const* tree : *trees)
{
- // Start the timer
- if ((*i)->timeLimit * IN_MILLISECONDS > timeLost)
+ if (m_timedAchievements.find(tree->ID) == m_timedAchievements.end() && !IsCompletedCriteriaTree(tree))
{
- m_timedAchievements[(*i)->ID] = (*i)->timeLimit * IN_MILLISECONDS - timeLost;
-
- // and at client too
- SetCriteriaProgress(*i, 0, GetOwner(), PROGRESS_SET);
+ // Start the timer
+ if (criteria->Entry->StartTimer * IN_MILLISECONDS > timeLost)
+ {
+ m_timedAchievements[tree->ID] = criteria->Entry->StartTimer * IN_MILLISECONDS - timeLost;
+ canStart = true;
+ }
}
}
+
+ if (!canStart)
+ continue;
+
+ // and at client too
+ SetCriteriaProgress(criteria, 0, GetOwner(), PROGRESS_SET);
}
}
template<class T>
void AchievementMgr<T>::RemoveTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry)
{
- AchievementCriteriaEntryList const& achievementCriteriaList = sAchievementMgr->GetTimedAchievementCriteriaByType(type);
- for (AchievementCriteriaEntryList::const_iterator i = achievementCriteriaList.begin(); i != achievementCriteriaList.end(); ++i)
+ AchievementCriteriaList const& achievementCriteriaList = sAchievementMgr->GetTimedAchievementCriteriaByType(type);
+ for (AchievementCriteria const* criteria : achievementCriteriaList)
{
- if ((*i)->timedCriteriaMiscId != entry)
+ if (criteria->Entry->StartAsset != entry)
continue;
- TimedAchievementMap::iterator timedIter = m_timedAchievements.find((*i)->ID);
- // We don't have timer for this achievement
- if (timedIter == m_timedAchievements.end())
- continue;
+ AchievementCriteriaTreeList const* trees = sAchievementMgr->GetAchievementCriteriaTreesByCriteria(criteria->ID);
+ // Remove the timer from all trees
+ for (AchievementCriteriaTree const* tree : *trees)
+ m_timedAchievements.erase(tree->ID);
// remove progress
- RemoveCriteriaProgress(*i);
-
- // Remove the timer
- m_timedAchievements.erase(timedIter);
+ RemoveCriteriaProgress(criteria);
}
}
@@ -2036,75 +2024,38 @@ struct VisibleAchievementPred
template<class T>
void AchievementMgr<T>::SendAllAchievementData(Player* /*receiver*/) const
{
- /*
VisibleAchievementPred isVisible;
- size_t numCriteria = m_criteriaProgress.size();
- size_t numAchievements = std::count_if(m_completedAchievements.begin(), m_completedAchievements.end(), isVisible);
- ByteBuffer criteriaData(numCriteria * (4 + 4 + 4 + 4 + 8 + 8));
- ObjectGuid guid = GetOwner()->GetGUID();
- ObjectGuid counter;
+ WorldPackets::Achievement::AllAchievements achievementData;
+ achievementData.Earned.reserve(m_completedAchievements.size());
+ achievementData.Progress.reserve(m_criteriaProgress.size());
- WorldPacket data(SMSG_ALL_ACHIEVEMENT_DATA, 4 + numAchievements * (4 + 4) + 4 + numCriteria * (4 + 4 + 4 + 4 + 8 + 8));
- data.WriteBits(numCriteria, 21);
- for (CriteriaProgressMap::const_iterator itr = m_criteriaProgress.begin(); itr != m_criteriaProgress.end(); ++itr)
+ for (auto itr = m_completedAchievements.begin(); itr != m_completedAchievements.end(); ++itr)
{
- counter.SetRawValue(itr->second.counter);
-
- data.WriteBit(guid[4]);
- data.WriteBit(counter[3]);
- data.WriteBit(guid[5]);
- data.WriteBit(counter[0]);
- data.WriteBit(counter[6]);
- data.WriteBit(guid[3]);
- data.WriteBit(guid[0]);
- data.WriteBit(counter[4]);
- data.WriteBit(guid[2]);
- data.WriteBit(counter[7]);
- data.WriteBit(guid[7]);
- data.WriteBits(0u, 2);
- data.WriteBit(guid[6]);
- data.WriteBit(counter[2]);
- data.WriteBit(counter[1]);
- data.WriteBit(counter[5]);
- data.WriteBit(guid[1]);
+ if (!isVisible(*itr))
+ continue;
- criteriaData.WriteByteSeq(guid[3]);
- criteriaData.WriteByteSeq(counter[5]);
- criteriaData.WriteByteSeq(counter[6]);
- criteriaData.WriteByteSeq(guid[4]);
- criteriaData.WriteByteSeq(guid[6]);
- criteriaData.WriteByteSeq(counter[2]);
- criteriaData << uint32(0); // timer 2
- criteriaData.WriteByteSeq(guid[2]);
- criteriaData << uint32(itr->first); // criteria id
- criteriaData.WriteByteSeq(guid[5]);
- criteriaData.WriteByteSeq(counter[0]);
- criteriaData.WriteByteSeq(counter[3]);
- criteriaData.WriteByteSeq(counter[1]);
- criteriaData.WriteByteSeq(counter[4]);
- criteriaData.WriteByteSeq(guid[0]);
- criteriaData.WriteByteSeq(guid[7]);
- criteriaData.WriteByteSeq(counter[7]);
- criteriaData << uint32(0); // timer 1
- criteriaData.AppendPackedTime(itr->second.date); // criteria date
- criteriaData.WriteByteSeq(guid[1]);
+ WorldPackets::Achievement::EarnedAchievement earned;
+ earned.Id = itr->first;
+ earned.Date = itr->second.date;
+ earned.Owner = GetOwner()->GetGUID();
+ earned.VirtualRealmAddress = earned.NativeRealmAddress = GetVirtualRealmAddress();
+ achievementData.Earned.push_back(earned);
}
- data.WriteBits(numAchievements, 23);
- data.FlushBits();
- data.append(criteriaData);
-
- for (CompletedAchievementMap::const_iterator itr = m_completedAchievements.begin(); itr != m_completedAchievements.end(); ++itr)
+ for (auto itr = m_criteriaProgress.begin(); itr != m_criteriaProgress.end(); ++itr)
{
- if (!isVisible(*itr))
- continue;
-
- data << uint32(itr->first);
- data.AppendPackedTime(itr->second.date);
+ WorldPackets::Achievement::CriteriaProgress progress;
+ progress.Id = itr->first;
+ progress.Quantity = itr->second.counter;
+ progress.Player = itr->second.PlayerGUID;
+ progress.Flags = 0;
+ progress.Date = itr->second.date;
+ progress.TimeFromStart = 0;
+ progress.TimeFromCreate = 0;
+ achievementData.Progress.push_back(progress);
}
- SendPacket(&data);
- */
+ SendPacket(achievementData.Write());
}
template<>
@@ -2227,7 +2178,7 @@ void AchievementMgr<Guild>::SendAchievementInfo(Player* receiver, uint32 achieve
{
/*
//will send response to criteria progress request
- AchievementCriteriaEntryList const* criteria = sAchievementMgr->GetAchievementCriteriaByAchievement(achievementId);
+ AchievementCriteriaTreeList const* criteria = sAchievementMgr->GetAchievementCriteriaByAchievement(achievementId);
if (!criteria)
{
// send empty packet
@@ -2243,7 +2194,7 @@ void AchievementMgr<Guild>::SendAchievementInfo(Player* receiver, uint32 achieve
uint32 numCriteria = 0;
ByteBuffer criteriaData(criteria->size() * (8 + 8 + 4 + 4 + 4));
ByteBuffer criteriaBits(criteria->size() * (8 + 8) / 8);
- for (AchievementCriteriaEntryList::const_iterator itr = criteria->begin(); itr != criteria->end(); ++itr)
+ for (AchievementCriteriaTreeList::const_iterator itr = criteria->begin(); itr != criteria->end(); ++itr)
{
uint32 criteriaId = (*itr)->ID;
CriteriaProgressMap::const_iterator progress = m_criteriaProgress.find(criteriaId);
@@ -2255,7 +2206,7 @@ void AchievementMgr<Guild>::SendAchievementInfo(Player* receiver, uint32 achieve
criteriaBits.WriteBits(numCriteria, 21);
- for (AchievementCriteriaEntryList::const_iterator itr = criteria->begin(); itr != criteria->end(); ++itr)
+ for (AchievementCriteriaTreeList::const_iterator itr = criteria->begin(); itr != criteria->end(); ++itr)
{
uint32 criteriaId = (*itr)->ID;
CriteriaProgressMap::const_iterator progress = m_criteriaProgress.find(criteriaId);
@@ -2263,7 +2214,7 @@ void AchievementMgr<Guild>::SendAchievementInfo(Player* receiver, uint32 achieve
continue;
counter.SetRawValue(progress->second.counter);
- guid = progress->second.CompletedGUID;
+ guid = progress->second.PlayerGUID;
criteriaBits.WriteBit(counter[4]);
criteriaBits.WriteBit(counter[1]);
@@ -2321,55 +2272,65 @@ bool AchievementMgr<T>::HasAchieved(uint32 achievementId) const
}
template<class T>
-bool AchievementMgr<T>::CanUpdateCriteria(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit const* unit, Player* referencePlayer)
+bool AchievementMgr<T>::CanUpdateCriteria(AchievementCriteria const* criteria, AchievementCriteriaTreeList const* trees, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit const* unit, Player* referencePlayer)
{
if (DisableMgr::IsDisabledFor(DISABLE_TYPE_ACHIEVEMENT_CRITERIA, criteria->ID, NULL))
{
- TC_LOG_TRACE("achievement", "CanUpdateCriteria: %s (Id: %u Type %s) Disabled",
- criteria->name, criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->type));
+ TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: %u Type %s) Disabled",
+ criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->Entry->Type));
return false;
}
- if (achievement->MapID != -1 && referencePlayer->GetMapId() != uint32(achievement->MapID))
+ bool treeRequirementPassed = false;
+ for (AchievementCriteriaTree const* tree : *trees)
{
- TC_LOG_TRACE("achievement", "CanUpdateCriteria: %s (Id: %u Type %s) Wrong map",
- criteria->name, criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->type));
- return false;
- }
+ if (HasAchieved(tree->Achievement->ID))
+ {
+ TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: %u Type %s Achievement %u) Achievement already earned",
+ criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->Entry->Type), tree->Achievement->ID);
+ continue;
+ }
- if ((achievement->Faction == ACHIEVEMENT_FACTION_HORDE && referencePlayer->GetTeam() != HORDE) ||
- (achievement->Faction == ACHIEVEMENT_FACTION_ALLIANCE && referencePlayer->GetTeam() != ALLIANCE))
- {
- TC_LOG_TRACE("achievement", "CanUpdateCriteria: %s (Id: %u Type %s) Wrong faction",
- criteria->name, criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->type));
- return false;
+ if (tree->Achievement->MapID != -1 && referencePlayer->GetMapId() != uint32(tree->Achievement->MapID))
+ {
+ TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: %u Type %s Achievement %u) Wrong map",
+ criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->Entry->Type), tree->Achievement->ID);
+ continue;
+ }
+
+ if ((tree->Achievement->Faction == ACHIEVEMENT_FACTION_HORDE && referencePlayer->GetTeam() != HORDE) ||
+ (tree->Achievement->Faction == ACHIEVEMENT_FACTION_ALLIANCE && referencePlayer->GetTeam() != ALLIANCE))
+ {
+ TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: %u Type %s Achievement %u) Wrong faction",
+ criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->Entry->Type), tree->Achievement->ID);
+ continue;
+ }
+
+ treeRequirementPassed = true;
+ break;
}
- if (IsCompletedCriteria(criteria, achievement))
- {
- TC_LOG_TRACE("achievement", "CanUpdateCriteria: %s (Id: %u Type %s) Is Completed",
- criteria->name, criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->type));
+ if (!treeRequirementPassed)
return false;
- }
if (!RequirementsSatisfied(criteria, miscValue1, miscValue2, miscValue3, unit, referencePlayer))
{
- TC_LOG_TRACE("achievement", "CanUpdateCriteria: %s (Id: %u Type %s) Requirements not satisfied",
- criteria->name, criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->type));
+ TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: %u Type %s) Requirements not satisfied",
+ criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->Entry->Type));
return false;
}
- if (!AdditionalRequirementsSatisfied(criteria, miscValue1, miscValue2, unit, referencePlayer))
+ if (criteria->Modifier && !AdditionalRequirementsSatisfied(criteria->Modifier, miscValue1, miscValue2, unit, referencePlayer))
{
- TC_LOG_TRACE("achievement", "CanUpdateCriteria: %s (Id: %u Type %s) Additional requirements not satisfied",
- criteria->name, criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->type));
+ TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: %u Type %s) Additional requirements not satisfied",
+ criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->Entry->Type));
return false;
}
if (!ConditionsSatisfied(criteria, referencePlayer))
{
- TC_LOG_TRACE("achievement", "CanUpdateCriteria: %s (Id: %u Type %s) Conditions not satisfied",
- criteria->name, criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->type));
+ TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: %u Type %s) Conditions not satisfied",
+ criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->Entry->Type));
return false;
}
@@ -2377,35 +2338,32 @@ bool AchievementMgr<T>::CanUpdateCriteria(AchievementCriteriaEntry const* criter
}
template<class T>
-bool AchievementMgr<T>::ConditionsSatisfied(AchievementCriteriaEntry const* criteria, Player* referencePlayer) const
+bool AchievementMgr<T>::ConditionsSatisfied(AchievementCriteria const* criteria, Player* referencePlayer) const
{
- for (uint32 i = 0; i < MAX_CRITERIA_REQUIREMENTS; ++i)
- {
- if (!criteria->additionalRequirements[i].additionalRequirement_type)
- continue;
+ if (!criteria->Entry->FailEvent)
+ return true;
- switch (criteria->additionalRequirements[i].additionalRequirement_type)
- {
- case ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP:
- if (referencePlayer->GetMapId() != criteria->additionalRequirements[i].additionalRequirement_value)
- return false;
- break;
- case ACHIEVEMENT_CRITERIA_CONDITION_NOT_IN_GROUP:
- if (referencePlayer->GetGroup())
- return false;
- break;
- default:
- break;
- }
+ switch (criteria->Entry->FailEvent)
+ {
+ case ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP:
+ if (!referencePlayer->InBattleground())
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_CONDITION_NOT_IN_GROUP:
+ if (referencePlayer->GetGroup())
+ return false;
+ break;
+ default:
+ break;
}
return true;
}
template<class T>
-bool AchievementMgr<T>::RequirementsSatisfied(AchievementCriteriaEntry const* achievementCriteria, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit const* unit, Player* referencePlayer) const
+bool AchievementMgr<T>::RequirementsSatisfied(AchievementCriteria const* achievementCriteria, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit const* unit, Player* referencePlayer) const
{
- switch (AchievementCriteriaTypes(achievementCriteria->type))
+ switch (AchievementCriteriaTypes(achievementCriteria->Entry->Type))
{
case ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS:
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST:
@@ -2460,57 +2418,36 @@ bool AchievementMgr<T>::RequirementsSatisfied(AchievementCriteriaEntry const* ac
case ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN:
break;
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT:
- if (m_completedAchievements.find(achievementCriteria->complete_achievement.linkedAchievement) == m_completedAchievements.end())
+ if (m_completedAchievements.find(achievementCriteria->Entry->Asset.AchievementID) == m_completedAchievements.end())
return false;
break;
case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG:
- if (!miscValue1 || achievementCriteria->win_bg.bgMapID != referencePlayer->GetMapId())
+ if (!miscValue1 || achievementCriteria->Entry->Asset.MapID != referencePlayer->GetMapId())
return false;
break;
case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE:
- if (!miscValue1 || achievementCriteria->kill_creature.creatureID != miscValue1)
+ if (!miscValue1 || achievementCriteria->Entry->Asset.CreatureID != miscValue1)
return false;
break;
case ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL:
- // update at loading or specific skill update
- if (miscValue1 && miscValue1 != achievementCriteria->reach_skill_level.skillID)
- return false;
- break;
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL:
// update at loading or specific skill update
- if (miscValue1 && miscValue1 != achievementCriteria->learn_skill_level.skillID)
+ if (miscValue1 && miscValue1 != achievementCriteria->Entry->Asset.SkillID)
return false;
break;
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE:
- if (miscValue1 && miscValue1 != achievementCriteria->complete_quests_in_zone.zoneID)
+ if (miscValue1 && miscValue1 != achievementCriteria->Entry->Asset.ZoneID)
return false;
break;
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND:
- if (!miscValue1 || referencePlayer->GetMapId() != achievementCriteria->complete_battleground.mapID)
- return false;
- break;
case ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP:
- if (!miscValue1 || referencePlayer->GetMapId() != achievementCriteria->death_at_map.mapID)
+ if (!miscValue1 || referencePlayer->GetMapId() != achievementCriteria->Entry->Asset.MapID)
return false;
break;
case ACHIEVEMENT_CRITERIA_TYPE_DEATH:
{
if (!miscValue1)
return false;
- // skip wrong arena achievements, if not achievIdByArenaSlot then normal total death counter
- bool notfit = false;
- for (int j = 0; j < MAX_ARENA_SLOT; ++j)
- {
- if (achievIdByArenaSlot[j] == achievementCriteria->achievement)
- {
- Battleground* bg = referencePlayer->GetBattleground();
- if (!bg || !bg->isArena() || ArenaTeam::GetSlotByType(bg->GetArenaType()) != j)
- notfit = true;
- break;
- }
- }
- if (notfit)
- return false;
break;
}
case ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON:
@@ -2522,45 +2459,13 @@ bool AchievementMgr<T>::RequirementsSatisfied(AchievementCriteriaEntry const* ac
if (!map || !map->IsDungeon())
return false;
- // search case
- bool found = false;
- for (int j = 0; achievIdForDungeon[j][0]; ++j)
- {
- if (achievIdForDungeon[j][0] == achievementCriteria->achievement)
- {
- if (map->IsRaid())
- {
- // if raid accepted (ignore difficulty)
- if (!achievIdForDungeon[j][2])
- break; // for
- }
- else if (referencePlayer->GetDungeonDifficulty() == DIFFICULTY_NORMAL)
- {
- // dungeon in normal mode accepted
- if (!achievIdForDungeon[j][1])
- break; // for
- }
- else
- {
- // dungeon in heroic mode accepted
- if (!achievIdForDungeon[j][3])
- break; // for
- }
-
- found = true;
- break; // for
- }
- }
- if (!found)
- return false;
-
//FIXME: work only for instances where max == min for players
- if (((InstanceMap*)map)->GetMaxPlayers() != achievementCriteria->death_in_dungeon.manLimit)
+ if (((InstanceMap*)map)->GetMaxPlayers() != achievementCriteria->Entry->Asset.GroupSize)
return false;
break;
}
case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE:
- if (!miscValue1 || miscValue1 != achievementCriteria->killed_by_creature.creatureEntry)
+ if (!miscValue1 || miscValue1 != achievementCriteria->Entry->Asset.CreatureID)
return false;
break;
case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER:
@@ -2568,7 +2473,7 @@ bool AchievementMgr<T>::RequirementsSatisfied(AchievementCriteriaEntry const* ac
return false;
break;
case ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM:
- if (!miscValue1 || miscValue2 != achievementCriteria->death_from.type)
+ if (!miscValue1 || miscValue2 != achievementCriteria->Entry->Asset.DamageType)
return false;
break;
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST:
@@ -2576,13 +2481,13 @@ bool AchievementMgr<T>::RequirementsSatisfied(AchievementCriteriaEntry const* ac
// if miscValues != 0, it contains the questID.
if (miscValue1)
{
- if (miscValue1 != achievementCriteria->complete_quest.questID)
+ if (miscValue1 != achievementCriteria->Entry->Asset.QuestID)
return false;
}
else
{
// login case.
- if (!referencePlayer->GetQuestRewardStatus(achievementCriteria->complete_quest.questID))
+ if (!referencePlayer->GetQuestRewardStatus(achievementCriteria->Entry->Asset.QuestID))
return false;
}
@@ -2593,42 +2498,37 @@ bool AchievementMgr<T>::RequirementsSatisfied(AchievementCriteriaEntry const* ac
}
case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET:
case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2:
- if (!miscValue1 || miscValue1 != achievementCriteria->be_spell_target.spellID)
- return false;
- break;
case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL:
case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2:
- if (!miscValue1 || miscValue1 != achievementCriteria->cast_spell.spellID)
+ if (!miscValue1 || miscValue1 != achievementCriteria->Entry->Asset.SpellID)
return false;
break;
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL:
- if (miscValue1 && miscValue1 != achievementCriteria->learn_spell.spellID)
+ if (miscValue1 && miscValue1 != achievementCriteria->Entry->Asset.SpellID)
return false;
- if (!referencePlayer->HasSpell(achievementCriteria->learn_spell.spellID))
+ if (!referencePlayer->HasSpell(achievementCriteria->Entry->Asset.SpellID))
return false;
break;
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE:
// miscValue1 = itemId - miscValue2 = count of item loot
// miscValue3 = loot_type (note: 0 = LOOT_CORPSE and then it ignored)
- if (!miscValue1 || !miscValue2 || !miscValue3 || miscValue3 != achievementCriteria->loot_type.lootType)
+ if (!miscValue1 || !miscValue2 || !miscValue3 || miscValue3 != achievementCriteria->Entry->Asset.LootType)
return false;
break;
case ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM:
- if (miscValue1 && achievementCriteria->own_item.itemID != miscValue1)
+ if (miscValue1 && achievementCriteria->Entry->Asset.ItemID != miscValue1)
return false;
break;
case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM:
- if (!miscValue1 || achievementCriteria->use_item.itemID != miscValue1)
- return false;
- break;
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM:
- if (!miscValue1 || miscValue1 != achievementCriteria->own_item.itemID)
+ case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM:
+ if (!miscValue1 || achievementCriteria->Entry->Asset.ItemID != miscValue1)
return false;
break;
case ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA:
{
- WorldMapOverlayEntry const* worldOverlayEntry = sWorldMapOverlayStore.LookupEntry(achievementCriteria->explore_area.areaReference);
+ WorldMapOverlayEntry const* worldOverlayEntry = sWorldMapOverlayStore.LookupEntry(achievementCriteria->Entry->Asset.WorldMapOverlayID);
if (!worldOverlayEntry)
break;
@@ -2658,19 +2558,19 @@ bool AchievementMgr<T>::RequirementsSatisfied(AchievementCriteriaEntry const* ac
break;
}
case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION:
- if (miscValue1 && miscValue1 != achievementCriteria->gain_reputation.factionID)
+ if (miscValue1 && miscValue1 != achievementCriteria->Entry->Asset.FactionID)
return false;
break;
case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM:
// miscValue1 = itemid miscValue2 = itemSlot
- if (!miscValue1 || miscValue2 != achievementCriteria->equip_epic_item.itemSlot)
+ if (!miscValue1 || miscValue2 != achievementCriteria->Entry->Asset.ItemSlot)
return false;
break;
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT:
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT:
{
// miscValue1 = itemid miscValue2 = diced value
- if (!miscValue1 || miscValue2 != achievementCriteria->roll_greed_on_loot.rollValue)
+ if (!miscValue1 || miscValue2 != achievementCriteria->Entry->Asset.RollValue)
return false;
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(uint32(miscValue1));
@@ -2679,7 +2579,7 @@ bool AchievementMgr<T>::RequirementsSatisfied(AchievementCriteriaEntry const* ac
break;
}
case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE:
- if (!miscValue1 || miscValue1 != achievementCriteria->do_emote.emoteID)
+ if (!miscValue1 || miscValue1 != achievementCriteria->Entry->Asset.EmoteID)
return false;
break;
case ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE:
@@ -2687,9 +2587,9 @@ bool AchievementMgr<T>::RequirementsSatisfied(AchievementCriteriaEntry const* ac
if (!miscValue1)
return false;
- if (achievementCriteria->additionalRequirements[0].additionalRequirement_type == ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP)
+ if (achievementCriteria->Entry->FailEvent == ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP)
{
- if (referencePlayer->GetMapId() != achievementCriteria->additionalRequirements[0].additionalRequirement_value)
+ if (!referencePlayer->InBattleground())
return false;
// map specific case (BG in fact) expected player targeted damage/heal
@@ -2697,21 +2597,13 @@ bool AchievementMgr<T>::RequirementsSatisfied(AchievementCriteriaEntry const* ac
return false;
}
break;
- case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM:
- // miscValue1 = item_id
- if (!miscValue1 || miscValue1 != achievementCriteria->equip_item.itemID)
- return false;
- break;
case ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT:
- if (!miscValue1 || miscValue1 != achievementCriteria->use_gameobject.goEntry)
- return false;
- break;
case ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT:
- if (!miscValue1 || miscValue1 != achievementCriteria->fish_in_gameobject.goEntry)
+ if (!miscValue1 || miscValue1 != achievementCriteria->Entry->Asset.GameObjectID)
return false;
break;
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS:
- if (miscValue1 && miscValue1 != achievementCriteria->learn_skillline_spell.skillLine)
+ if (miscValue1 && miscValue1 != achievementCriteria->Entry->Asset.SkillID)
return false;
break;
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM:
@@ -2725,32 +2617,32 @@ bool AchievementMgr<T>::RequirementsSatisfied(AchievementCriteriaEntry const* ac
break;
}
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE:
- if (miscValue1 && miscValue1 != achievementCriteria->learn_skill_line.skillLine)
+ if (miscValue1 && miscValue1 != achievementCriteria->Entry->Asset.SkillID)
return false;
break;
case ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS:
- if (!miscValue1 || miscValue1 != achievementCriteria->hk_class.classID)
+ if (!miscValue1 || miscValue1 != achievementCriteria->Entry->Asset.ClassID)
return false;
break;
case ACHIEVEMENT_CRITERIA_TYPE_HK_RACE:
- if (!miscValue1 || miscValue1 != achievementCriteria->hk_race.raceID)
+ if (!miscValue1 || miscValue1 != achievementCriteria->Entry->Asset.RaceID)
return false;
break;
case ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE:
- if (!miscValue1 || miscValue1 != achievementCriteria->bg_objective.objectiveId)
+ if (!miscValue1 || miscValue1 != achievementCriteria->Entry->Asset.ObjectiveId)
return false;
break;
case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA:
- if (!miscValue1 || miscValue1 != achievementCriteria->honorable_kill_at_area.areaID)
+ if (!miscValue1 || miscValue1 != achievementCriteria->Entry->Asset.AreaID)
return false;
break;
case ACHIEVEMENT_CRITERIA_TYPE_CURRENCY:
if (!miscValue1 || !miscValue2 || int64(miscValue2) < 0
- || miscValue1 != achievementCriteria->currencyGain.currency)
+ || miscValue1 != achievementCriteria->Entry->Asset.CurrencyID)
return false;
break;
case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA:
- if (miscValue1 != achievementCriteria->win_arena.mapID)
+ if (miscValue1 != achievementCriteria->Entry->Asset.MapID)
return false;
break;
default:
@@ -2760,137 +2652,148 @@ bool AchievementMgr<T>::RequirementsSatisfied(AchievementCriteriaEntry const* ac
}
template<class T>
-bool AchievementMgr<T>::AdditionalRequirementsSatisfied(AchievementCriteriaEntry const* criteria, uint64 miscValue1, uint64 /*miscValue2*/, Unit const* unit, Player* referencePlayer) const
+bool AchievementMgr<T>::AdditionalRequirementsSatisfied(ModifierTreeNode const* tree, uint64 miscValue1, uint64 miscValue2, Unit const* unit, Player* referencePlayer) const
{
- for (uint8 i = 0; i < MAX_ADDITIONAL_CRITERIA_CONDITIONS; ++i)
- {
- uint32 reqType = criteria->additionalConditionType[i];
- uint32 reqValue = criteria->additionalConditionValue[i];
+ for (ModifierTreeNode const* node : tree->Children)
+ if (!AdditionalRequirementsSatisfied(node, miscValue1, miscValue2, unit, referencePlayer))
+ return false;
+
+ uint32 reqType = tree->Entry->Type;
+ if (!reqType)
+ return true;
+
+ uint32 reqValue = tree->Entry->Asset[0];
- switch (AchievementCriteriaAdditionalCondition(reqType))
+ switch (AchievementCriteriaAdditionalCondition(reqType))
+ {
+ case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_CREATURE_ENTRY: // 4
+ if (!unit || unit->GetEntry() != reqValue)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_PLAYER: // 5
+ if (!unit || unit->GetTypeId() != TYPEID_PLAYER)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_DEAD: // 6
+ if (!unit || unit->IsAlive())
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_ENEMY: // 7
+ if (!unit || !referencePlayer->IsHostileTo(unit))
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_HAS_AURA: // 8
+ if (!referencePlayer->HasAura(reqValue))
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_HAS_AURA: // 10
+ if (!unit || !unit->HasAura(reqValue))
+ return false;
+ case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_HAS_AURA_TYPE: // 11
+ if (!unit || !unit->HasAuraType(AuraType(reqValue)))
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_ITEM_QUALITY_MIN: // 14
{
- case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_CREATURE_ENTRY: // 4
- if (!unit || unit->GetEntry() != reqValue)
- return false;
- break;
- case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_PLAYER: // 5
- if (!unit || unit->GetTypeId() != TYPEID_PLAYER)
- return false;
- break;
- case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_DEAD: // 6
- if (!unit || unit->IsAlive())
- return false;
- break;
- case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_ENEMY: // 7
- if (!unit || !referencePlayer->IsHostileTo(unit))
- return false;
- break;
- case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_HAS_AURA: // 8
- if (!referencePlayer->HasAura(reqValue))
- return false;
- break;
- case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_HAS_AURA: // 10
- if (!unit || !unit->HasAura(reqValue))
- return false;
- case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_HAS_AURA_TYPE: // 11
- if (!unit || !unit->HasAuraType(AuraType(reqValue)))
- return false;
- break;
- case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_ITEM_QUALITY_MIN: // 14
- {
- // miscValue1 is itemid
- ItemTemplate const* const item = sObjectMgr->GetItemTemplate(uint32(miscValue1));
- if (!item || item->GetQuality() < reqValue)
- return false;
- break;
- }
- case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_ITEM_QUALITY_EQUALS: // 15
- {
- // miscValue1 is itemid
- ItemTemplate const* const item = sObjectMgr->GetItemTemplate(uint32(miscValue1));
- if (!item || item->GetQuality() != reqValue)
- return false;
- break;
- }
- case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_AREA_OR_ZONE: // 17
- {
- uint32 zoneId, areaId;
- referencePlayer->GetZoneAndAreaId(zoneId, areaId);
- if (zoneId != reqValue && areaId != reqValue)
- return false;
- break;
- }
- case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_AREA_OR_ZONE: // 18
- {
- if (!unit)
- return false;
- uint32 zoneId, areaId;
- unit->GetZoneAndAreaId(zoneId, areaId);
- if (zoneId != reqValue && areaId != reqValue)
- return false;
- break;
- }
- case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_MAP_DIFFICULTY: // 20
- if (uint32(referencePlayer->GetMap()->GetDifficulty()) != reqValue)
- return false;
- break;
- case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_RACE: // 25
- if (referencePlayer->getRace() != reqValue)
- return false;
- break;
- case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_CLASS: // 26
- if (referencePlayer->getClass() != reqValue)
- return false;
- break;
- case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_RACE: // 27
- if (!unit || unit->GetTypeId() != TYPEID_PLAYER || unit->getRace() != reqValue)
- return false;
- break;
- case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_CLASS: // 28
- if (!unit || unit->GetTypeId() != TYPEID_PLAYER || unit->getClass() != reqValue)
- return false;
- break;
- case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_MAX_GROUP_MEMBERS: // 29
- if (referencePlayer->GetGroup() && referencePlayer->GetGroup()->GetMembersCount() >= reqValue)
- return false;
- break;
- case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_CREATURE_TYPE: // 30
- {
- if (!unit)
- return false;
- Creature const* const creature = unit->ToCreature();
- if (!creature || creature->GetCreatureType() != reqValue)
- return false;
- break;
- }
- case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_MAP: // 32
- if (referencePlayer->GetMapId() != reqValue)
- return false;
- break;
- case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TITLE_BIT_INDEX: // 38
- // miscValue1 is title's bit index
- if (miscValue1 != reqValue)
- return false;
- break;
- case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_LEVEL: // 39
- if (referencePlayer->getLevel() != reqValue)
- return false;
- break;
- case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_LEVEL: // 40
- if (!unit || unit->getLevel() != reqValue)
- return false;
- break;
- case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_ZONE: // 41
- if (!unit || unit->GetZoneId() != reqValue)
- return false;
- break;
- case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_HEALTH_PERCENT_BELOW: // 46
- if (!unit || unit->GetHealthPct() >= reqValue)
- return false;
- break;
- default:
- break;
+ // miscValue1 is itemid
+ ItemTemplate const* const item = sObjectMgr->GetItemTemplate(uint32(miscValue1));
+ if (!item || item->GetQuality() < reqValue)
+ return false;
+ break;
}
+ case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_ITEM_QUALITY_EQUALS: // 15
+ {
+ // miscValue1 is itemid
+ ItemTemplate const* const item = sObjectMgr->GetItemTemplate(uint32(miscValue1));
+ if (!item || item->GetQuality() != reqValue)
+ return false;
+ break;
+ }
+ case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_AREA_OR_ZONE: // 17
+ {
+ uint32 zoneId, areaId;
+ referencePlayer->GetZoneAndAreaId(zoneId, areaId);
+ if (zoneId != reqValue && areaId != reqValue)
+ return false;
+ break;
+ }
+ case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_AREA_OR_ZONE: // 18
+ {
+ if (!unit)
+ return false;
+ uint32 zoneId, areaId;
+ unit->GetZoneAndAreaId(zoneId, areaId);
+ if (zoneId != reqValue && areaId != reqValue)
+ return false;
+ break;
+ }
+ case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_MAP_DIFFICULTY: // 20
+ if (uint32(referencePlayer->GetMap()->GetDifficulty()) != reqValue)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_ARENA_TYPE:
+ {
+ Battleground* bg = referencePlayer->GetBattleground();
+ if (!bg || !bg->isArena() || bg->GetArenaType() != reqValue)
+ return false;
+ break;
+ }
+ case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_RACE: // 25
+ if (referencePlayer->getRace() != reqValue)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_CLASS: // 26
+ if (referencePlayer->getClass() != reqValue)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_RACE: // 27
+ if (!unit || unit->GetTypeId() != TYPEID_PLAYER || unit->getRace() != reqValue)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_CLASS: // 28
+ if (!unit || unit->GetTypeId() != TYPEID_PLAYER || unit->getClass() != reqValue)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_MAX_GROUP_MEMBERS: // 29
+ if (referencePlayer->GetGroup() && referencePlayer->GetGroup()->GetMembersCount() >= reqValue)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_CREATURE_TYPE: // 30
+ {
+ if (!unit)
+ return false;
+ Creature const* const creature = unit->ToCreature();
+ if (!creature || creature->GetCreatureType() != reqValue)
+ return false;
+ break;
+ }
+ case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_MAP: // 32
+ if (referencePlayer->GetMapId() != reqValue)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TITLE_BIT_INDEX: // 38
+ // miscValue1 is title's bit index
+ if (miscValue1 != reqValue)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_LEVEL: // 39
+ if (referencePlayer->getLevel() != reqValue)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_LEVEL: // 40
+ if (!unit || unit->getLevel() != reqValue)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_ZONE: // 41
+ if (!unit || unit->GetZoneId() != reqValue)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_HEALTH_PERCENT_BELOW: // 46
+ if (!unit || unit->GetHealthPct() >= reqValue)
+ return false;
+ break;
+ default:
+ break;
}
return true;
}
@@ -3134,35 +3037,166 @@ template class AchievementMgr<Guild>;
template class AchievementMgr<Player>;
//==========================================================
+AchievementGlobalMgr::~AchievementGlobalMgr()
+{
+ for (AchievementCriteriaTreeMap::iterator itr = _achievementCriteriaTrees.begin(); itr != _achievementCriteriaTrees.end(); ++itr)
+ delete itr->second;
+
+ for (AchievementCriteriaMap::iterator itr = _achievementCriteria.begin(); itr != _achievementCriteria.end(); ++itr)
+ delete itr->second;
+
+ for (ModifierTreeMap::iterator itr = _criteriaModifiers.begin(); itr != _criteriaModifiers.end(); ++itr)
+ delete itr->second;
+}
+
+void AchievementGlobalMgr::LoadAchievementCriteriaModifiersTree()
+{
+ uint32 oldMSTime = getMSTime();
+
+ if (sModifierTreeStore.GetNumRows() == 0)
+ {
+ TC_LOG_ERROR("server.loading", ">> Loaded 0 achievement criteria modifiers.");
+ return;
+ }
+
+ // Load modifier tree nodes
+ for (uint32 i = 0; i < sModifierTreeStore.GetNumRows(); ++i)
+ {
+ ModifierTreeEntry const* tree = sModifierTreeStore.LookupEntry(i);
+ if (!tree)
+ continue;
+
+ ModifierTreeNode* node = new ModifierTreeNode();
+ node->Entry = tree;
+ _criteriaModifiers[node->Entry->ID] = node;
+ }
+
+ // Build tree
+ for (auto itr = _criteriaModifiers.begin(); itr != _criteriaModifiers.end(); ++itr)
+ {
+ if (!itr->second->Entry->Parent)
+ continue;
+
+ auto parent = _criteriaModifiers.find(itr->second->Entry->Parent);
+ if (parent != _criteriaModifiers.end())
+ parent->second->Children.push_back(itr->second);
+ }
+
+ TC_LOG_INFO("server.loading", ">> Loaded %u achievement criteria modifiers in %u ms", uint32(_criteriaModifiers.size()), GetMSTimeDiffToNow(oldMSTime));
+}
+
void AchievementGlobalMgr::LoadAchievementCriteriaList()
{
uint32 oldMSTime = getMSTime();
- if (sAchievementCriteriaStore.GetNumRows() == 0)
+ if (sCriteriaTreeStore.GetNumRows() == 0)
{
TC_LOG_ERROR("server.loading", ">> Loaded 0 achievement criteria.");
return;
}
+ std::unordered_map<uint32 /*criteriaTreeID*/, AchievementEntry const*> achievementCriteriaTreeIds;
+ for (uint32 i = 0; i < sAchievementStore.GetNumRows(); ++i)
+ if (AchievementEntry const* achievement = sAchievementStore.LookupEntry(i))
+ if (achievement->CriteriaTree)
+ achievementCriteriaTreeIds[achievement->CriteriaTree] = achievement;
+
+ // Load criteria tree nodes
+ for (uint32 i = 0; i < sCriteriaTreeStore.GetNumRows(); ++i)
+ {
+ CriteriaTreeEntry const* tree = sCriteriaTreeStore.LookupEntry(i);
+ if (!tree)
+ continue;
+
+ // Find linked achievement
+ auto achievementItr = achievementCriteriaTreeIds.find(tree->ID);
+ CriteriaTreeEntry const* cur = tree;
+ while (achievementItr == achievementCriteriaTreeIds.end())
+ {
+ if (!tree->Parent)
+ break;
+
+ cur = sCriteriaTreeStore.LookupEntry(cur->Parent);
+ if (!cur)
+ break;
+
+ achievementItr = achievementCriteriaTreeIds.find(cur->ID);
+ }
+
+ if (achievementItr == achievementCriteriaTreeIds.end())
+ continue;
+
+ AchievementCriteriaTree* achievementCriteriaTree = new AchievementCriteriaTree();
+ achievementCriteriaTree->ID = i;
+ achievementCriteriaTree->Achievement = achievementItr->second;
+ achievementCriteriaTree->Entry = tree;
+ achievementCriteriaTree->Criteria = nullptr;
+
+ _achievementCriteriaTrees[achievementCriteriaTree->Entry->ID] = achievementCriteriaTree;
+ if (sCriteriaStore.LookupEntry(tree->CriteriaID))
+ _achievementCriteriaTreeByCriteria[tree->CriteriaID].push_back(achievementCriteriaTree);
+ }
+
+ // Build tree
+ for (auto itr = _achievementCriteriaTrees.begin(); itr != _achievementCriteriaTrees.end(); ++itr)
+ {
+ if (!itr->second->Entry->Parent)
+ continue;
+
+ auto parent = _achievementCriteriaTrees.find(itr->second->Entry->Parent);
+ if (parent != _achievementCriteriaTrees.end())
+ parent->second->Children.push_back(itr->second);
+ }
+
+ // Load criteria
uint32 criterias = 0;
uint32 guildCriterias = 0;
- for (uint32 entryId = 0; entryId < sAchievementCriteriaStore.GetNumRows(); ++entryId)
+ for (uint32 i = 0; i < sCriteriaStore.GetNumRows(); ++i)
{
- AchievementCriteriaEntry const* criteria = sAchievementMgr->GetAchievementCriteria(entryId);
+ CriteriaEntry const* criteria = sCriteriaStore.LookupEntry(i);
if (!criteria)
continue;
- AchievementEntry const* achievement = sAchievementMgr->GetAchievement(criteria->achievement);
-
- m_AchievementCriteriaListByAchievement[criteria->achievement].push_back(criteria);
+ auto treeItr = _achievementCriteriaTreeByCriteria.find(i);
+ if (treeItr == _achievementCriteriaTreeByCriteria.end())
+ continue;
- if (achievement && achievement->Flags & ACHIEVEMENT_FLAG_GUILD)
- ++guildCriterias, m_GuildAchievementCriteriasByType[criteria->type].push_back(criteria);
+ AchievementCriteria* achievementCriteria = new AchievementCriteria();
+ achievementCriteria->ID = i;
+ achievementCriteria->Entry = criteria;
+ auto mod = _criteriaModifiers.find(criteria->ModifierTreeId);
+ if (mod != _criteriaModifiers.end())
+ achievementCriteria->Modifier = mod->second;
else
- ++criterias, m_AchievementCriteriasByType[criteria->type].push_back(criteria);
+ achievementCriteria->Modifier = nullptr;
+
+ _achievementCriteria[achievementCriteria->ID] = achievementCriteria;
+
+ bool isGuild = false, isPlayer = false;
+ for (AchievementCriteriaTree const* tree : treeItr->second)
+ {
+ const_cast<AchievementCriteriaTree*>(tree)->Criteria = achievementCriteria;
- if (criteria->timeLimit)
- m_AchievementCriteriasByTimedType[criteria->timedCriteriaStartType].push_back(criteria);
+ if (tree->Achievement->Flags & ACHIEVEMENT_FLAG_GUILD)
+ isGuild = true;
+ else
+ isPlayer = true;
+ }
+
+ if (isGuild)
+ {
+ ++guildCriterias;
+ _guildAchievementCriteriasByType[criteria->Type].push_back(achievementCriteria);
+ }
+
+ if (isPlayer)
+ {
+ ++criterias;
+ _achievementCriteriasByType[criteria->Type].push_back(achievementCriteria);
+ }
+
+ if (criteria->StartTimer)
+ _achievementCriteriasByTimedType[criteria->StartEvent].push_back(achievementCriteria);
}
TC_LOG_INFO("server.loading", ">> Loaded %u achievement criteria and %u guild achievement crieteria in %u ms", criterias, guildCriterias, GetMSTimeDiffToNow(oldMSTime));
@@ -3186,13 +3220,13 @@ void AchievementGlobalMgr::LoadAchievementReferenceList()
if (!achievement || !achievement->SharesCriteria)
continue;
- m_AchievementListByReferencedId[achievement->SharesCriteria].push_back(achievement);
+ _achievementListByReferencedId[achievement->SharesCriteria].push_back(achievement);
++count;
}
// Once Bitten, Twice Shy (10 player) - Icecrown Citadel
if (AchievementEntry const* achievement = sAchievementMgr->GetAchievement(4539))
- const_cast<AchievementEntry*>(achievement)->MapID = 631; // Correct map requirement (currently has Ulduar)
+ const_cast<AchievementEntry*>(achievement)->MapID = 631; // Correct map requirement (currently has Ulduar); 6.0.3 note - it STILL has ulduar requirement
TC_LOG_INFO("server.loading", ">> Loaded %u achievement references in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
@@ -3201,7 +3235,7 @@ void AchievementGlobalMgr::LoadAchievementCriteriaData()
{
uint32 oldMSTime = getMSTime();
- m_criteriaDataMap.clear(); // need for reload case
+ _criteriaDataMap.clear(); // need for reload case
QueryResult result = WorldDatabase.Query("SELECT criteria_id, type, value1, value2, ScriptName FROM achievement_criteria_data");
@@ -3218,7 +3252,7 @@ void AchievementGlobalMgr::LoadAchievementCriteriaData()
Field* fields = result->Fetch();
uint32 criteria_id = fields[0].GetUInt32();
- AchievementCriteriaEntry const* criteria = sAchievementMgr->GetAchievementCriteria(criteria_id);
+ AchievementCriteria const* criteria = sAchievementMgr->GetAchievementCriteria(criteria_id);
if (!criteria)
{
@@ -3243,7 +3277,7 @@ void AchievementGlobalMgr::LoadAchievementCriteriaData()
continue;
// this will allocate empty data set storage
- AchievementCriteriaDataSet& dataSet = m_criteriaDataMap[criteria_id];
+ AchievementCriteriaDataSet& dataSet = _criteriaDataMap[criteria_id];
dataSet.SetCriteriaId(criteria_id);
// add real data only for not NONE data types
@@ -3288,18 +3322,18 @@ void AchievementGlobalMgr::LoadCompletedAchievements()
continue;
}
else if (achievement->Flags & (ACHIEVEMENT_FLAG_REALM_FIRST_REACH | ACHIEVEMENT_FLAG_REALM_FIRST_KILL))
- m_allCompletedAchievements[achievementId] = uint32(0xFFFFFFFF);
+ _allCompletedAchievements[achievementId] = uint32(0xFFFFFFFF);
}
while (result->NextRow());
- TC_LOG_INFO("server.loading", ">> Loaded %lu realm first completed achievements in %u ms", (unsigned long)m_allCompletedAchievements.size(), GetMSTimeDiffToNow(oldMSTime));
+ TC_LOG_INFO("server.loading", ">> Loaded %lu realm first completed achievements in %u ms", (unsigned long)_allCompletedAchievements.size(), GetMSTimeDiffToNow(oldMSTime));
}
void AchievementGlobalMgr::LoadRewards()
{
uint32 oldMSTime = getMSTime();
- m_achievementRewards.clear(); // need for reload case
+ _achievementRewards.clear(); // need for reload case
// 0 1 2 3 4 5 6 7
QueryResult result = WorldDatabase.Query("SELECT entry, title_A, title_H, item, sender, subject, text, mailTemplate FROM achievement_reward");
@@ -3406,7 +3440,7 @@ void AchievementGlobalMgr::LoadRewards()
}
}
- m_achievementRewards[entry] = reward;
+ _achievementRewards[entry] = reward;
++count;
}
while (result->NextRow());
@@ -3418,7 +3452,7 @@ void AchievementGlobalMgr::LoadRewardLocales()
{
uint32 oldMSTime = getMSTime();
- m_achievementRewardLocales.clear(); // need for reload case
+ _achievementRewardLocales.clear(); // need for reload case
QueryResult result = WorldDatabase.Query("SELECT entry, subject_loc1, text_loc1, subject_loc2, text_loc2, subject_loc3, text_loc3, subject_loc4, text_loc4, "
"subject_loc5, text_loc5, subject_loc6, text_loc6, subject_loc7, text_loc7, subject_loc8, text_loc8"
@@ -3436,13 +3470,13 @@ void AchievementGlobalMgr::LoadRewardLocales()
uint32 entry = fields[0].GetUInt32();
- if (m_achievementRewards.find(entry) == m_achievementRewards.end())
+ if (_achievementRewards.find(entry) == _achievementRewards.end())
{
TC_LOG_ERROR("sql.sql", "Table `locales_achievement_reward` (Entry: %u) has locale strings for non-existing achievement reward.", entry);
continue;
}
- AchievementRewardLocale& data = m_achievementRewardLocales[entry];
+ AchievementRewardLocale& data = _achievementRewardLocales[entry];
for (uint8 i = TOTAL_LOCALES - 1; i > 0; --i)
{
@@ -3453,7 +3487,7 @@ void AchievementGlobalMgr::LoadRewardLocales()
}
while (result->NextRow());
- TC_LOG_INFO("server.loading", ">> Loaded %u achievement reward locale strings in %u ms", uint32(m_achievementRewardLocales.size()), GetMSTimeDiffToNow(oldMSTime));
+ TC_LOG_INFO("server.loading", ">> Loaded %u achievement reward locale strings in %u ms", uint32(_achievementRewardLocales.size()), GetMSTimeDiffToNow(oldMSTime));
}
AchievementEntry const* AchievementGlobalMgr::GetAchievement(uint32 achievementId) const
@@ -3461,14 +3495,27 @@ AchievementEntry const* AchievementGlobalMgr::GetAchievement(uint32 achievementI
return sAchievementStore.LookupEntry(achievementId);
}
-AchievementCriteriaEntry const* AchievementGlobalMgr::GetAchievementCriteria(uint32 criteriaId) const
+AchievementCriteriaTree const* AchievementGlobalMgr::GetAchievementCriteriaTree(uint32 criteriaTreeId) const
{
- return sAchievementCriteriaStore.LookupEntry(criteriaId);
+ auto itr = _achievementCriteriaTrees.find(criteriaTreeId);
+ if (itr == _achievementCriteriaTrees.end())
+ return nullptr;
+
+ return itr->second;
+}
+
+AchievementCriteria const* AchievementGlobalMgr::GetAchievementCriteria(uint32 criteriaId) const
+{
+ auto itr = _achievementCriteria.find(criteriaId);
+ if (itr == _achievementCriteria.end())
+ return nullptr;
+
+ return itr->second;
}
void AchievementGlobalMgr::OnInstanceDestroyed(uint32 instanceId)
{
- for (auto& realmCompletion : m_allCompletedAchievements)
+ for (auto& realmCompletion : _allCompletedAchievements)
if (realmCompletion.second == instanceId)
realmCompletion.second = uint32(0xFFFFFFFF);
}