aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Achievements/AchievementMgr.cpp1329
-rw-r--r--src/server/game/Achievements/AchievementMgr.h133
-rw-r--r--src/server/game/DataStores/DBCEnums.h18
-rw-r--r--src/server/game/DataStores/DBCStores.cpp25
-rw-r--r--src/server/game/DataStores/DBCStores.h4
-rw-r--r--src/server/game/DataStores/DBCStructure.h608
-rw-r--r--src/server/game/DataStores/DBCfmt.h8
-rw-r--r--src/server/game/Guilds/Guild.cpp6
-rw-r--r--src/server/game/Guilds/Guild.h2
-rw-r--r--src/server/game/Server/Packets/AchievementPackets.cpp74
-rw-r--r--src/server/game/Server/Packets/AchievementPackets.h93
-rw-r--r--src/server/game/Server/Protocol/Opcodes.cpp6
-rw-r--r--src/server/game/Server/Protocol/Opcodes.h12
-rw-r--r--src/server/game/World/World.cpp2
14 files changed, 1123 insertions, 1197 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);
}
diff --git a/src/server/game/Achievements/AchievementMgr.h b/src/server/game/Achievements/AchievementMgr.h
index 90d52cd9101..05b30c73e76 100644
--- a/src/server/game/Achievements/AchievementMgr.h
+++ b/src/server/game/Achievements/AchievementMgr.h
@@ -32,17 +32,45 @@ class Unit;
class Player;
class WorldPacket;
-typedef std::vector<AchievementCriteriaEntry const*> AchievementCriteriaEntryList;
-typedef std::vector<AchievementEntry const*> AchievementEntryList;
+struct ModifierTreeNode
+{
+ ModifierTreeEntry const* Entry;
+ std::vector<ModifierTreeNode const*> Children;
+};
+
+typedef std::unordered_map<uint32, ModifierTreeNode*> ModifierTreeMap;
+
+struct AchievementCriteria
+{
+ uint32 ID;
+ CriteriaEntry const* Entry;
+ ModifierTreeNode const* Modifier;
+};
+
+typedef std::vector<AchievementCriteria const*> AchievementCriteriaList;
+typedef std::unordered_map<uint32, AchievementCriteria*> AchievementCriteriaMap;
-typedef std::unordered_map<uint32, AchievementCriteriaEntryList> AchievementCriteriaListByAchievement;
-typedef std::unordered_map<uint32, AchievementEntryList> AchievementListByReferencedId;
+struct AchievementCriteriaTree
+{
+ uint32 ID;
+ CriteriaTreeEntry const* Entry;
+ AchievementEntry const* Achievement;
+ AchievementCriteria const* Criteria;
+ std::vector<AchievementCriteriaTree const*> Children;
+};
+
+typedef std::unordered_map<uint32, AchievementCriteriaTree*> AchievementCriteriaTreeMap;
+typedef std::vector<AchievementCriteriaTree const*> AchievementCriteriaTreeList;
+typedef std::vector<AchievementEntry const*> AchievementEntryList;
+typedef std::unordered_map<uint32, AchievementCriteriaTreeList> AchievementCriteriaTreeByCriteriaMap;
+
+typedef std::unordered_map<uint32, AchievementEntryList> AchievementListByReferencedId;
struct CriteriaProgress
{
uint64 counter;
time_t date; // latest update time.
- ObjectGuid CompletedGUID; // GUID of the player that completed this criteria (guild achievements)
+ ObjectGuid PlayerGUID; // GUID of the player that completed this criteria (guild achievements)
bool changed;
};
@@ -193,7 +221,7 @@ struct AchievementCriteriaData
ScriptId = _scriptId;
}
- bool IsValid(AchievementCriteriaEntry const* criteria);
+ bool IsValid(AchievementCriteria const* criteria);
bool Meets(uint32 criteria_id, Player const* source, Unit const* target, uint32 miscValue1 = 0) const;
};
@@ -276,32 +304,34 @@ class AchievementMgr
uint32 GetAchievementPoints() const { return _achievementPoints; }
private:
void SendAchievementEarned(AchievementEntry const* achievement) const;
- void SendCriteriaUpdate(AchievementCriteriaEntry const* entry, CriteriaProgress const* progress, uint32 timeElapsed, bool timedCompleted) const;
- CriteriaProgress* GetCriteriaProgress(AchievementCriteriaEntry const* entry);
- void SetCriteriaProgress(AchievementCriteriaEntry const* entry, uint64 changeValue, Player* referencePlayer, ProgressType ptype = PROGRESS_SET);
- void RemoveCriteriaProgress(AchievementCriteriaEntry const* entry);
+ void SendCriteriaUpdate(AchievementCriteria const* entry, CriteriaProgress const* progress, uint32 timeElapsed, bool timedCompleted) const;
+ CriteriaProgress* GetCriteriaProgress(AchievementCriteria const* entry);
+ void SetCriteriaProgress(AchievementCriteria const* entry, uint64 changeValue, Player* referencePlayer, ProgressType ptype = PROGRESS_SET);
+ void RemoveCriteriaProgress(AchievementCriteria const* entry);
void CompletedCriteriaFor(AchievementEntry const* achievement, Player* referencePlayer);
- bool IsCompletedCriteria(AchievementCriteriaEntry const* achievementCriteria, AchievementEntry const* achievement);
+ bool IsCompletedCriteriaTree(AchievementCriteriaTree const* tree);
+ bool IsCompletedCriteria(AchievementCriteria const* achievementCriteria, uint64 requiredAmount);
+ uint64 GetTotalCriteriaTreeProgress(AchievementCriteriaTree const* criteriaTree);
bool IsCompletedAchievement(AchievementEntry const* entry);
- bool CanUpdateCriteria(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit const* unit, Player* referencePlayer);
- void SendPacket(WorldPacket* data) const;
+ bool CanUpdateCriteria(AchievementCriteria const* criteria, AchievementCriteriaTreeList const* trees, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit const* unit, Player* referencePlayer);
+ void SendPacket(WorldPacket const* data) const;
- bool ConditionsSatisfied(AchievementCriteriaEntry const* criteria, Player* referencePlayer) const;
- bool RequirementsSatisfied(AchievementCriteriaEntry const* criteria, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit const* unit, Player* referencePlayer) const;
- bool AdditionalRequirementsSatisfied(AchievementCriteriaEntry const* criteria, uint64 miscValue1, uint64 miscValue2, Unit const* unit, Player* referencePlayer) const;
+ bool ConditionsSatisfied(AchievementCriteria const* criteria, Player* referencePlayer) const;
+ bool RequirementsSatisfied(AchievementCriteria const* criteria, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit const* unit, Player* referencePlayer) const;
+ bool AdditionalRequirementsSatisfied(ModifierTreeNode const* parent, uint64 miscValue1, uint64 miscValue2, Unit const* unit, Player* referencePlayer) const;
T* _owner;
CriteriaProgressMap m_criteriaProgress;
CompletedAchievementMap m_completedAchievements;
typedef std::map<uint32, uint32> TimedAchievementMap;
- TimedAchievementMap m_timedAchievements; // Criteria id/time left in MS
+ TimedAchievementMap m_timedAchievements; // Criteria tree id/time left in MS
uint32 _achievementPoints;
};
class AchievementGlobalMgr
{
AchievementGlobalMgr() { }
- ~AchievementGlobalMgr() { }
+ ~AchievementGlobalMgr();
public:
static char const* GetCriteriaTypeString(AchievementCriteriaTypes type);
@@ -313,50 +343,50 @@ class AchievementGlobalMgr
return &instance;
}
- AchievementCriteriaEntryList const& GetAchievementCriteriaByType(AchievementCriteriaTypes type, bool guild = false) const
+ AchievementCriteriaTreeList const* GetAchievementCriteriaTreesByCriteria(uint32 criteriaId) const
{
- return guild ? m_GuildAchievementCriteriasByType[type] : m_AchievementCriteriasByType[type];
+ auto itr = _achievementCriteriaTreeByCriteria.find(criteriaId);
+ return itr != _achievementCriteriaTreeByCriteria.end() ? &itr->second : nullptr;
}
- AchievementCriteriaEntryList const& GetTimedAchievementCriteriaByType(AchievementCriteriaTimedTypes type) const
+ AchievementCriteriaList const& GetAchievementCriteriaByType(AchievementCriteriaTypes type, bool guild = false) const
{
- return m_AchievementCriteriasByTimedType[type];
+ return guild ? _guildAchievementCriteriasByType[type] : _achievementCriteriasByType[type];
}
- AchievementCriteriaEntryList const* GetAchievementCriteriaByAchievement(uint32 id) const
+ AchievementCriteriaList const& GetTimedAchievementCriteriaByType(AchievementCriteriaTimedTypes type) const
{
- AchievementCriteriaListByAchievement::const_iterator itr = m_AchievementCriteriaListByAchievement.find(id);
- return itr != m_AchievementCriteriaListByAchievement.end() ? &itr->second : NULL;
+ return _achievementCriteriasByTimedType[type];
}
AchievementEntryList const* GetAchievementByReferencedId(uint32 id) const
{
- AchievementListByReferencedId::const_iterator itr = m_AchievementListByReferencedId.find(id);
- return itr != m_AchievementListByReferencedId.end() ? &itr->second : NULL;
+ AchievementListByReferencedId::const_iterator itr = _achievementListByReferencedId.find(id);
+ return itr != _achievementListByReferencedId.end() ? &itr->second : NULL;
}
AchievementReward const* GetAchievementReward(AchievementEntry const* achievement) const
{
- AchievementRewards::const_iterator iter = m_achievementRewards.find(achievement->ID);
- return iter != m_achievementRewards.end() ? &iter->second : NULL;
+ AchievementRewards::const_iterator iter = _achievementRewards.find(achievement->ID);
+ return iter != _achievementRewards.end() ? &iter->second : NULL;
}
AchievementRewardLocale const* GetAchievementRewardLocale(AchievementEntry const* achievement) const
{
- AchievementRewardLocales::const_iterator iter = m_achievementRewardLocales.find(achievement->ID);
- return iter != m_achievementRewardLocales.end() ? &iter->second : NULL;
+ AchievementRewardLocales::const_iterator iter = _achievementRewardLocales.find(achievement->ID);
+ return iter != _achievementRewardLocales.end() ? &iter->second : NULL;
}
- AchievementCriteriaDataSet const* GetCriteriaDataSet(AchievementCriteriaEntry const* achievementCriteria) const
+ AchievementCriteriaDataSet const* GetCriteriaDataSet(AchievementCriteria const* achievementCriteria) const
{
- AchievementCriteriaDataMap::const_iterator iter = m_criteriaDataMap.find(achievementCriteria->ID);
- return iter != m_criteriaDataMap.end() ? &iter->second : NULL;
+ AchievementCriteriaDataMap::const_iterator iter = _criteriaDataMap.find(achievementCriteria->ID);
+ return iter != _criteriaDataMap.end() ? &iter->second : NULL;
}
bool IsRealmCompleted(AchievementEntry const* achievement, uint32 instanceId) const
{
- AllCompletedAchievements::const_iterator itr = m_allCompletedAchievements.find(achievement->ID);
- if (itr == m_allCompletedAchievements.end())
+ AllCompletedAchievements::const_iterator itr = _allCompletedAchievements.find(achievement->ID);
+ if (itr == _allCompletedAchievements.end())
return false;
if (achievement->Flags & ACHIEVEMENT_FLAG_REALM_FIRST_KILL)
@@ -370,7 +400,7 @@ class AchievementGlobalMgr
if (IsRealmCompleted(achievement, instanceId))
return;
- m_allCompletedAchievements[achievement->ID] = instanceId;
+ _allCompletedAchievements[achievement->ID] = instanceId;
}
bool IsGroupCriteriaType(AchievementCriteriaTypes type) const
@@ -394,6 +424,7 @@ class AchievementGlobalMgr
// Removes instanceId as valid id to complete realm first kill achievements
void OnInstanceDestroyed(uint32 instanceId);
+ void LoadAchievementCriteriaModifiersTree();
void LoadAchievementCriteriaList();
void LoadAchievementCriteriaData();
void LoadAchievementReferenceList();
@@ -401,27 +432,31 @@ class AchievementGlobalMgr
void LoadRewards();
void LoadRewardLocales();
AchievementEntry const* GetAchievement(uint32 achievementId) const;
- AchievementCriteriaEntry const* GetAchievementCriteria(uint32 achievementId) const;
+ AchievementCriteriaTree const* GetAchievementCriteriaTree(uint32 criteriaTreeId) const;
+ AchievementCriteria const* GetAchievementCriteria(uint32 criteriaId) const;
private:
- AchievementCriteriaDataMap m_criteriaDataMap;
+ AchievementCriteriaDataMap _criteriaDataMap;
- // store achievement criterias by type to speed up lookup
- AchievementCriteriaEntryList m_AchievementCriteriasByType[ACHIEVEMENT_CRITERIA_TYPE_TOTAL];
- AchievementCriteriaEntryList m_GuildAchievementCriteriasByType[ACHIEVEMENT_CRITERIA_TYPE_TOTAL];
+ AchievementCriteriaTreeMap _achievementCriteriaTrees;
+ AchievementCriteriaMap _achievementCriteria;
+ ModifierTreeMap _criteriaModifiers;
+
+ AchievementCriteriaTreeByCriteriaMap _achievementCriteriaTreeByCriteria;
- AchievementCriteriaEntryList m_AchievementCriteriasByTimedType[ACHIEVEMENT_TIMED_TYPE_MAX];
+ // store achievement criterias by type to speed up lookup
+ AchievementCriteriaList _achievementCriteriasByType[ACHIEVEMENT_CRITERIA_TYPE_TOTAL];
+ AchievementCriteriaList _guildAchievementCriteriasByType[ACHIEVEMENT_CRITERIA_TYPE_TOTAL];
- // store achievement criterias by achievement to speed up lookup
- AchievementCriteriaListByAchievement m_AchievementCriteriaListByAchievement;
+ AchievementCriteriaList _achievementCriteriasByTimedType[ACHIEVEMENT_TIMED_TYPE_MAX];
// store achievements by referenced achievement id to speed up lookup
- AchievementListByReferencedId m_AchievementListByReferencedId;
+ AchievementListByReferencedId _achievementListByReferencedId;
typedef std::map<uint32 /*achievementId*/, uint32 /*instanceId*/> AllCompletedAchievements;
- AllCompletedAchievements m_allCompletedAchievements;
+ AllCompletedAchievements _allCompletedAchievements;
- AchievementRewards m_achievementRewards;
- AchievementRewardLocales m_achievementRewardLocales;
+ AchievementRewards _achievementRewards;
+ AchievementRewardLocales _achievementRewardLocales;
};
#define sAchievementMgr AchievementGlobalMgr::instance()
diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h
index 3187b5f9f77..8b93ba5222b 100644
--- a/src/server/game/DataStores/DBCEnums.h
+++ b/src/server/game/DataStores/DBCEnums.h
@@ -93,12 +93,6 @@ enum AchievementFlags
ACHIEVEMENT_FLAG_SHOW_CRITERIA_MEMBERS = 0x00010000 //
};
-enum AchievementCriteriaLimits
-{
- MAX_CRITERIA_REQUIREMENTS = 2,
- MAX_ADDITIONAL_CRITERIA_CONDITIONS = 3
-};
-
enum AchievementCriteriaCondition
{
ACHIEVEMENT_CRITERIA_CONDITION_NONE = 0,
@@ -132,7 +126,7 @@ enum AchievementCriteriaAdditionalCondition
ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_AREA_OR_ZONE = 18,
ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_MAP_DIFFICULTY = 20,
ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_CREATURE_YIELDS_XP = 21, // NYI
- ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_ARENA_TYPE = 24, // NYI
+ ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_ARENA_TYPE = 24,
ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_RACE = 25,
ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_CLASS = 26,
ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_RACE = 27,
@@ -179,6 +173,8 @@ enum AchievementCriteriaTimedTypes
ACHIEVEMENT_TIMED_TYPE_CREATURE = 7, // Timer is started by killing creature with entry in timerStartEvent
ACHIEVEMENT_TIMED_TYPE_ITEM = 9, // Timer is started by using item with entry in timerStartEvent
ACHIEVEMENT_TIMED_TYPE_UNK = 10, // Unknown
+ ACHIEVEMENT_TIMED_TYPE_UNK_2 = 13, // Unknown
+ ACHIEVEMENT_TIMED_TYPE_SCENARIO_STAGE = 14, // Timer is started by changing stages in a scenario
ACHIEVEMENT_TIMED_TYPE_MAX
};
@@ -299,7 +295,13 @@ enum AchievementCriteriaTypes
ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE = 139 //struct { uint32 count; } Guild Challenge
};
-#define ACHIEVEMENT_CRITERIA_TYPE_TOTAL 140
+#define ACHIEVEMENT_CRITERIA_TYPE_TOTAL 188
+
+enum AchievementCriteriaTreeOperator
+{
+ ACHIEVEMENT_CRITERIA_TREE_OPERATOR_ALL = 4,
+ ACHIEVEMENT_CRITERIA_TREE_OPERATOR_ANY = 8
+};
enum AreaFlags
{
diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp
index b801fd7b3f3..6647fa08fc2 100644
--- a/src/server/game/DataStores/DBCStores.cpp
+++ b/src/server/game/DataStores/DBCStores.cpp
@@ -60,7 +60,6 @@ static AreaFlagByMapID sAreaFlagByMapID; // for instances wit
static WMOAreaInfoByTripple sWMOAreaInfoByTripple;
DBCStorage <AchievementEntry> sAchievementStore(Achievementfmt);
-DBCStorage <AchievementCriteriaEntry> sAchievementCriteriaStore(AchievementCriteriafmt);
DBCStorage <AreaTriggerEntry> sAreaTriggerStore(AreaTriggerEntryfmt);
DBCStorage <ArmorLocationEntry> sArmorLocationStore(ArmorLocationfmt);
DBCStorage <AuctionHouseEntry> sAuctionHouseStore(AuctionHouseEntryfmt);
@@ -85,6 +84,8 @@ DBCStorage <CreatureFamilyEntry> sCreatureFamilyStore(CreatureFamilyfmt);
DBCStorage <CreatureModelDataEntry> sCreatureModelDataStore(CreatureModelDatafmt);
DBCStorage <CreatureSpellDataEntry> sCreatureSpellDataStore(CreatureSpellDatafmt);
DBCStorage <CreatureTypeEntry> sCreatureTypeStore(CreatureTypefmt);
+DBCStorage <CriteriaEntry> sCriteriaStore(Criteriafmt);
+DBCStorage <CriteriaTreeEntry> sCriteriaTreeStore(CriteriaTreefmt);
DBCStorage <CurrencyTypesEntry> sCurrencyTypesStore(CurrencyTypesfmt);
uint32 PowersByClass[MAX_CLASSES][MAX_POWERS];
@@ -163,6 +164,7 @@ DBCStorage <MapEntry> sMapStore(MapEntryfmt);
DBCStorage <MapDifficultyEntry> sMapDifficultyStore(MapDifficultyEntryfmt); // only for loading
MapDifficultyMap sMapDifficultyMap;
+DBCStorage <ModifierTreeEntry> sModifierTreeStore(ModifierTreefmt);
DBCStorage <MovieEntry> sMovieStore(MovieEntryfmt);
DBCStorage <MountCapabilityEntry> sMountCapabilityStore(MountCapabilityfmt);
DBCStorage <MountTypeEntry> sMountTypeStore(MountTypefmt);
@@ -240,19 +242,13 @@ typedef std::list<std::string> StoreProblemList;
uint32 DBCFileCount = 0;
-static bool LoadDBC_assert_print(uint32 fsize, uint32 rsize, const std::string& filename)
-{
- TC_LOG_ERROR("misc", "Size of '%s' set by format string (%u) not equal size of C++ structure (%u).", filename.c_str(), fsize, rsize);
-
- // ASSERT must fail after function call
- return false;
-}
-
template<class T>
inline void LoadDBC(uint32& availableDbcLocales, StoreProblemList& errors, DBCStorage<T>& storage, std::string const& dbcPath, std::string const& filename, std::string const* customFormat = NULL, std::string const* customIndexName = NULL)
{
// compatibility format and C++ structure sizes
- ASSERT(DBCFileLoader::GetFormatRecordSize(storage.GetFormat()) == sizeof(T) || LoadDBC_assert_print(DBCFileLoader::GetFormatRecordSize(storage.GetFormat()), sizeof(T), filename));
+ ASSERT(DBCFileLoader::GetFormatRecordSize(storage.GetFormat()) == sizeof(T),
+ "Size of '%s' set by format string (%u) not equal size of C++ structure (%u).",
+ filename.c_str(), DBCFileLoader::GetFormatRecordSize(storage.GetFormat()), sizeof(T));
++DBCFileCount;
std::string dbcFilename = dbcPath + filename;
@@ -298,7 +294,9 @@ template<class T>
inline void LoadGameTable(StoreProblemList& errors, std::string const& tableName, GameTable<T>& storage, std::string const& dbcPath, std::string const& filename)
{
// compatibility format and C++ structure sizes
- ASSERT(DBCFileLoader::GetFormatRecordSize(storage.GetFormat()) == sizeof(T) || LoadDBC_assert_print(DBCFileLoader::GetFormatRecordSize(storage.GetFormat()), sizeof(T), filename));
+ ASSERT(DBCFileLoader::GetFormatRecordSize(storage.GetFormat()) == sizeof(T),
+ "Size of '%s' set by format string (%u) not equal size of C++ structure (%u).",
+ filename.c_str(), DBCFileLoader::GetFormatRecordSize(storage.GetFormat()), sizeof(T));
++DBCFileCount;
std::string dbcFilename = dbcPath + filename;
@@ -365,8 +363,6 @@ void LoadDBCStores(const std::string& dataPath)
}
LoadDBC(availableDbcLocales, bad_dbc_files, sAchievementStore, dbcPath, "Achievement.dbc"/*, &CustomAchievementfmt, &CustomAchievementIndex*/);//19116
- // TODO: 6.x remove this and update achievement system with new dbcs
- //LoadDBC(availableDbcLocales, bad_dbc_files, sAchievementCriteriaStore, dbcPath, "Achievement_Criteria.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sAreaTriggerStore, dbcPath, "AreaTrigger.dbc");//19116
LoadDBC(availableDbcLocales, bad_dbc_files, sAreaGroupStore, dbcPath, "AreaGroup.dbc");//19116
LoadDBC(availableDbcLocales, bad_dbc_files, sAuctionHouseStore, dbcPath, "AuctionHouse.dbc");//19116
@@ -415,6 +411,8 @@ void LoadDBCStores(const std::string& dataPath)
LoadDBC(availableDbcLocales, bad_dbc_files, sCreatureModelDataStore, dbcPath, "CreatureModelData.dbc");//19116
LoadDBC(availableDbcLocales, bad_dbc_files, sCreatureSpellDataStore, dbcPath, "CreatureSpellData.dbc");//19116
LoadDBC(availableDbcLocales, bad_dbc_files, sCreatureTypeStore, dbcPath, "CreatureType.dbc");//19116
+ LoadDBC(availableDbcLocales, bad_dbc_files, sCriteriaStore, dbcPath, "Criteria.dbc");//19342
+ LoadDBC(availableDbcLocales, bad_dbc_files, sCriteriaTreeStore, dbcPath, "CriteriaTree.dbc");//19342
LoadDBC(availableDbcLocales, bad_dbc_files, sCurrencyTypesStore, dbcPath, "CurrencyTypes.dbc");//19116
LoadDBC(availableDbcLocales, bad_dbc_files, sDestructibleModelDataStore, dbcPath, "DestructibleModelData.dbc");//19116
LoadDBC(availableDbcLocales, bad_dbc_files, sDungeonEncounterStore, dbcPath, "DungeonEncounter.dbc");//19116
@@ -499,6 +497,7 @@ void LoadDBCStores(const std::string& dataPath)
sMapDifficultyMap[MAKE_PAIR32(entry->MapID, entry->DifficultyID)] = MapDifficulty(entry->RaidDuration, entry->MaxPlayers, entry->Message_lang[0] > 0);
sMapDifficultyStore.Clear();
+ LoadDBC(availableDbcLocales, bad_dbc_files, sModifierTreeStore, dbcPath, "ModifierTree.dbc");//19342
LoadDBC(availableDbcLocales, bad_dbc_files, sMountCapabilityStore, dbcPath, "MountCapability.dbc");//19116
LoadDBC(availableDbcLocales, bad_dbc_files, sMountTypeStore, dbcPath, "MountType.dbc");//19116
diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h
index 0c25e359483..92770e2e618 100644
--- a/src/server/game/DataStores/DBCStores.h
+++ b/src/server/game/DataStores/DBCStores.h
@@ -131,7 +131,6 @@ private:
};
extern DBCStorage <AchievementEntry> sAchievementStore;
-extern DBCStorage <AchievementCriteriaEntry> sAchievementCriteriaStore;
extern DBCStorage <AreaTableEntry> sAreaStore;// recommend access using functions
extern DBCStorage <AreaGroupEntry> sAreaGroupStore;
extern DBCStorage <AreaTriggerEntry> sAreaTriggerStore;
@@ -156,6 +155,8 @@ extern DBCStorage <CreatureFamilyEntry> sCreatureFamilyStore;
extern DBCStorage <CreatureModelDataEntry> sCreatureModelDataStore;
extern DBCStorage <CreatureSpellDataEntry> sCreatureSpellDataStore;
extern DBCStorage <CreatureTypeEntry> sCreatureTypeStore;
+extern DBCStorage <CriteriaEntry> sCriteriaStore;
+extern DBCStorage <CriteriaTreeEntry> sCriteriaTreeStore;
extern DBCStorage <CurrencyTypesEntry> sCurrencyTypesStore;
extern DBCStorage <DestructibleModelDataEntry> sDestructibleModelDataStore;
extern DBCStorage <DungeonEncounterEntry> sDungeonEncounterStore;
@@ -217,6 +218,7 @@ extern DBCStorage <LockEntry> sLockStore;
extern DBCStorage <MailTemplateEntry> sMailTemplateStore;
extern DBCStorage <MapEntry> sMapStore;
extern DBCStorage <MinorTalentEntry> sMinorTalentStore;
+extern DBCStorage <ModifierTreeEntry> sModifierTreeStore;
extern DBCStorage <MountCapabilityEntry> sMountCapabilityStore;
extern DBCStorage <MountTypeEntry> sMountTypeStore;
extern DBCStorage <NameGenEntry> sNameGenStore;
diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h
index a03f6370c62..32bd3c35fee 100644
--- a/src/server/game/DataStores/DBCStructure.h
+++ b/src/server/game/DataStores/DBCStructure.h
@@ -54,7 +54,7 @@ struct AchievementEntry
//char* Reward_lang; // 11
uint32 MinimumCriteria; // 12 - need this count of completed criterias (own or referenced achievement criterias)
uint32 SharesCriteria; // 13 - referenced achievement (counting of all completed criterias)
- //uint32 CriteriaTree; // 14
+ uint32 CriteriaTree; // 14
};
//19116
@@ -66,474 +66,6 @@ struct AchievementCategoryEntry
//uint32 UIOrder; // 3
};
-struct AchievementCriteriaEntry
-{
- uint32 ID; // 0
- uint32 achievement; // 1
- uint32 type; // 2
- union
- {
- // ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE = 0
- /// @todo also used for player deaths..
- struct
- {
- uint32 creatureID; // 3
- uint64 creatureCount; // 4
- } kill_creature;
-
- // ACHIEVEMENT_CRITERIA_TYPE_WIN_BG = 1
- struct
- {
- uint32 bgMapID; // 3
- uint64 winCount; // 4
- } win_bg;
-
- // ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL = 5
- // ACHIEVEMENT_CRITERIA_TYPE_REACH_GUILD_LEVEL = 125
- struct
- {
- uint32 unused; // 3
- uint64 level; // 4
- } reach_level;
-
- // ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL = 7
- struct
- {
- uint32 skillID; // 3
- uint64 skillLevel; // 4
- } reach_skill_level;
-
- // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT = 8
- struct
- {
- uint32 linkedAchievement; // 3
- } complete_achievement;
-
- // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT = 9
- struct
- {
- uint32 unused; // 3
- uint64 totalQuestCount; // 4
- } complete_quest_count;
-
- // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY = 10
- struct
- {
- uint32 unused; // 3
- uint64 numberOfDays; // 4
- } complete_daily_quest_daily;
-
- // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE = 11
- struct
- {
- uint32 zoneID; // 3
- uint64 questCount; // 4
- } complete_quests_in_zone;
-
- // ACHIEVEMENT_CRITERIA_TYPE_CURRENCY = 12
- struct
- {
- uint32 currency;
- uint64 count;
- } currencyGain;
-
- // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST = 14
- struct
- {
- uint32 unused; // 3
- uint64 questCount; // 4
- } complete_daily_quest;
-
- // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND = 15
- struct
- {
- uint32 mapID; // 3
- } complete_battleground;
-
- // ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP = 16
- struct
- {
- uint32 mapID; // 3
- } death_at_map;
-
- // ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON = 18
- struct
- {
- uint32 manLimit; // 3
- } death_in_dungeon;
-
- // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID = 19
- struct
- {
- uint32 groupSize; // 3 can be 5, 10 or 25
- } complete_raid;
-
- // ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE = 20
- struct
- {
- uint32 creatureEntry; // 3
- } killed_by_creature;
-
- // ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING = 24
- struct
- {
- uint32 unused; // 3
- uint64 fallHeight; // 4
- } fall_without_dying;
-
- // ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM = 26
- struct
- {
- uint32 type; // 3, see enum EnviromentalDamage
- } death_from;
-
- // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST = 27
- struct
- {
- uint32 questID; // 3
- uint64 questCount; // 4
- } complete_quest;
-
- // ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET = 28
- // ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2 = 69
- struct
- {
- uint32 spellID; // 3
- uint64 spellCount; // 4
- } be_spell_target;
-
- // ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL = 29
- // ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2 = 110
- struct
- {
- uint32 spellID; // 3
- uint64 castCount; // 4
- } cast_spell;
-
- // ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE
- struct
- {
- uint32 objectiveId; // 3
- uint64 completeCount; // 4
- } bg_objective;
-
- // ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA = 31
- struct
- {
- uint32 areaID; // 3 Reference to AreaTable.dbc
- uint64 killCount; // 4
- } honorable_kill_at_area;
-
- // ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA = 32
- struct
- {
- uint32 mapID; // 3 Reference to Map.dbc
- uint64 count; // 4 Number of times that the arena must be won.
- } win_arena;
-
- // ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA = 33
- struct
- {
- uint32 mapID; // 3 Reference to Map.dbc
- } play_arena;
-
- // ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL = 34
- struct
- {
- uint32 spellID; // 3 Reference to Map.dbc
- } learn_spell;
-
- // ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM = 36
- struct
- {
- uint32 itemID; // 3
- uint64 itemCount; // 4
- } own_item;
-
- // ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA = 37
- struct
- {
- uint32 unused; // 3
- uint64 count; // 4
- } win_rated_arena;
-
- // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING = 38
- struct
- {
- uint32 teamtype; // 3 {2, 3, 5}
- } highest_team_rating;
-
- // ACHIEVEMENT_CRITERIA_TYPE_REACH_TEAM_RATING = 39
- struct
- {
- uint32 teamtype; // 3 {2, 3, 5}
- uint64 teamrating; // 4
- } reach_team_rating;
-
- // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_PERSONAL_RATING = 39
- struct
- {
- uint32 teamtype; // 3 {2, 3, 5}
- uint64 PersonalRating; // 4
- } highest_personal_rating;
-
- // ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL = 40
- struct
- {
- uint32 skillID; // 3
- uint64 skillLevel; // 4 apprentice=1, journeyman=2, expert=3, artisan=4, master=5, grand master=6
- } learn_skill_level;
-
- // ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM = 41
- struct
- {
- uint32 itemID; // 3
- uint64 itemCount; // 4
- } use_item;
-
- // ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM = 42
- struct
- {
- uint32 itemID; // 3
- uint64 itemCount; // 4
- } loot_item;
-
- // ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA = 43
- struct
- {
- /// @todo This rank is _NOT_ the index from AreaTable.dbc
- uint32 areaReference; // 3
- } explore_area;
-
- // ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK = 44
- struct
- {
- /// @todo This rank is _NOT_ the index from CharTitles.dbc
- uint32 rank; // 3
- } own_rank;
-
- // ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT = 45
- struct
- {
- uint32 unused; // 3
- uint64 numberOfSlots; // 4
- } buy_bank_slot;
-
- // ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION = 46
- struct
- {
- uint32 factionID; // 3
- uint64 reputationAmount; // 4 Total reputation amount, so 42000 = exalted
- } gain_reputation;
-
- // ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION= 47
- struct
- {
- uint32 unused; // 3
- uint64 numberOfExaltedFactions; // 4
- } gain_exalted_reputation;
-
- // ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP = 48
- struct
- {
- uint32 unused; // 3
- uint64 numberOfVisits; // 4
- } visit_barber;
-
- // ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM = 49
- /// @todo where is the required itemlevel stored?
- struct
- {
- uint32 itemSlot; // 3
- uint64 count; // 4
- } equip_epic_item;
-
- // ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT = 50
- struct
- {
- uint32 rollValue; // 3
- uint64 count; // 4
- } roll_need_on_loot;
- // ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT = 51
- struct
- {
- uint32 rollValue; // 3
- uint64 count; // 4
- } roll_greed_on_loot;
-
- // ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS = 52
- struct
- {
- uint32 classID; // 3
- uint64 count; // 4
- } hk_class;
-
- // ACHIEVEMENT_CRITERIA_TYPE_HK_RACE = 53
- struct
- {
- uint32 raceID; // 3
- uint64 count; // 4
- } hk_race;
-
- // ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE = 54
- /// @todo where is the information about the target stored?
- struct
- {
- uint32 emoteID; // 3 enum TextEmotes
- uint64 count; // 4 count of emotes, always required special target or requirements
- } do_emote;
- // ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE = 13
- // ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE = 55
- // ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS = 56
- struct
- {
- uint32 unused; // 3
- uint64 count; // 4
- } healing_done;
-
- // ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS = 56
- struct
- {
- uint32 unused;
- uint64 killCount;
- } get_killing_blow;
-
- // ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM = 57
- struct
- {
- uint32 itemID; // 3
- uint64 count; // 4
- } equip_item;
-
- // ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD= 62
- struct
- {
- uint32 unused; // 3
- uint64 goldInCopper; // 4
- } quest_reward_money;
-
- // ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY = 67
- struct
- {
- uint32 unused; // 3
- uint64 goldInCopper; // 4
- } loot_money;
-
- // ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT = 68
- struct
- {
- uint32 goEntry; // 3
- uint64 useCount; // 4
- } use_gameobject;
-
- // ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL = 70
- /// @todo are those special criteria stored in the dbc or do we have to add another sql table?
- struct
- {
- uint32 unused; // 3
- uint64 killCount; // 4
- } special_pvp_kill;
-
- // ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT = 72
- struct
- {
- uint32 goEntry; // 3
- uint64 lootCount; // 4
- } fish_in_gameobject;
-
- // ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS = 75
- struct
- {
- uint32 skillLine; // 3
- uint64 spellCount; // 4
- } learn_skillline_spell;
-
- // ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL = 76
- struct
- {
- uint32 unused; // 3
- uint64 duelCount; // 4
- } win_duel;
-
- // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_POWER = 96
- struct
- {
- uint32 powerType; // 3 mana=0, 1=rage, 3=energy, 6=runic power
- } highest_power;
-
- // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_STAT = 97
- struct
- {
- uint32 statType; // 3 4=spirit, 3=int, 2=stamina, 1=agi, 0=strength
- } highest_stat;
-
- // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_SPELLPOWER = 98
- struct
- {
- uint32 spellSchool; // 3
- } highest_spellpower;
-
- // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_RATING = 100
- struct
- {
- uint32 ratingType; // 3
- } highest_rating;
-
- // ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE = 109
- struct
- {
- uint32 lootType; // 3 3=fishing, 2=pickpocket, 4=disentchant
- uint64 lootTypeCount; // 4
- } loot_type;
-
- // ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE = 112
- struct
- {
- uint32 skillLine; // 3
- uint64 spellCount; // 4
- } learn_skill_line;
-
- // ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL = 113
- struct
- {
- uint32 unused; // 3
- uint64 killCount; // 4
- } honorable_kill;
-
- struct
- {
- uint32 unused;
- uint64 dungeonsComplete;
- } use_lfg;
-
- struct
- {
- uint32 field3; // 3 main requirement
- uint64 count; // 4 main requirement count
- } raw;
- };
-
- struct
- {
- uint32 additionalRequirement_type;
- uint32 additionalRequirement_value;
- } additionalRequirements[MAX_CRITERIA_REQUIREMENTS];
-
- char* name; // 9 m_description_lang
- uint32 completionFlag; // 10 m_flags
- uint32 timedCriteriaStartType; // 11 m_timer_start_event Only appears with timed achievements, seems to be the type of starting a timed Achievement, only type 1 and some of type 6 need manual starting
- // 1: ByEventId(?) (serverside IDs), 2: ByQuestId, 5: ByCastSpellId(?)
- // 6: BySpellIdTarget(some of these are unknown spells, some not, some maybe spells)
- // 7: ByKillNpcId, 9: ByUseItemId
- uint32 timedCriteriaMiscId; // 12 m_timer_asset_id Alway appears with timed events, used internally to start the achievement, store
- uint32 timeLimit; // 13 m_timer_time time limit in seconds
- uint32 showOrder; // 14 m_ui_order also used in achievement shift-links as index in state bitmask
- //uint32 unk1; // 15 only one value, still unknown
- //uint32 unk2; // 16 all zeros
- uint32 additionalConditionType[MAX_ADDITIONAL_CRITERIA_CONDITIONS]; // 17-19
- uint32 additionalConditionValue[MAX_ADDITIONAL_CRITERIA_CONDITIONS]; // 20-22
-};
-
// Temporary define until max depth is found somewhere (adt?)
#define MAX_MAP_DEPTH -5000
@@ -897,6 +429,134 @@ struct CreatureTypeEntry
//uint32 Flags; // 2 no exp? critters, non-combat pets, gas cloud.
};
+struct CriteriaEntry
+{
+ uint32 ID; // 0
+ uint32 Type; // 1
+ union
+ {
+ uint32 ID;
+ // ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE = 0
+ // ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE = 20
+ uint32 CreatureID;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_WIN_BG = 1
+ // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND = 15
+ // ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP = 16
+ // ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA = 32
+ // ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA = 33
+ uint32 MapID;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL = 7
+ // ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL = 40
+ // ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS = 75
+ // ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE = 112
+ uint32 SkillID;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT = 8
+ uint32 AchievementID;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE = 11
+ uint32 ZoneID;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_CURRENCY = 12
+ uint32 CurrencyID;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON = 18
+ // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID = 19
+ uint32 GroupSize;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM = 26
+ uint32 DamageType;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST = 27
+ uint32 QuestID;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET = 28
+ // ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2 = 69
+ // ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL = 29
+ // ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2 = 110
+ // ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL = 34
+ uint32 SpellID;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE
+ uint32 ObjectiveId;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA = 31
+ uint32 AreaID;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM = 36
+ // ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM = 41
+ // ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM = 42
+ // ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM = 57
+ uint32 ItemID;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING = 38
+ // ACHIEVEMENT_CRITERIA_TYPE_REACH_TEAM_RATING = 39
+ // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_PERSONAL_RATING = 39
+ uint32 TeamType;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA = 43
+ uint32 WorldMapOverlayID;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION = 46
+ uint32 FactionID;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM = 49
+ uint32 ItemSlot;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT = 50
+ // ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT = 51
+ uint32 RollValue;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS = 52
+ uint32 ClassID;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_HK_RACE = 53
+ uint32 RaceID;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE = 54
+ uint32 EmoteID;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT = 68
+ // ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT = 72
+ uint32 GameObjectID;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_POWER = 96
+ uint32 PowerType;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_STAT = 97
+ uint32 StatType;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_SPELLPOWER = 98
+ uint32 SpellSchool;
+
+ // ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE = 109
+ uint32 LootType;
+ } Asset; // 2
+ uint32 StartEvent; // 3
+ uint32 StartAsset; // 4
+ uint32 StartTimer; // 5
+ uint32 FailEvent; // 6
+ uint32 FailAsset; // 7
+ uint32 ModifierTreeId; // 8
+ //uint32 Flags; // 9
+ uint32 EligibilityWorldStateID; // 10
+ uint32 EligibilityWorldStateValue; // 11
+};
+
+struct CriteriaTreeEntry
+{
+ uint32 ID; // 0
+ uint32 CriteriaID; // 1
+ uint64 Amount; // 2
+ uint32 Operator; // 3
+ uint32 Parent; // 4
+ //uint32 Flags; // 5
+ //char* DescriptionLang; // 6
+ //uint32 OrderIndex; // 7
+};
+
/* not used
struct CurrencyCategoryEntry
{
@@ -1567,6 +1227,16 @@ struct MinorTalentEntry
uint32 OrderIndex; // 3
};
+struct ModifierTreeEntry
+{
+ uint32 ID; // 0
+ uint32 Type; // 1
+ uint32 Asset[2]; // 2-3
+ uint32 Operator; // 4
+ uint32 Amount; // 5
+ uint32 Parent; // 6
+};
+
struct MountCapabilityEntry
{
uint32 ID; // 0
diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h
index 852af09fdb2..bbba02b5ea5 100644
--- a/src/server/game/DataStores/DBCfmt.h
+++ b/src/server/game/DataStores/DBCfmt.h
@@ -20,12 +20,11 @@
#define TRINITY_DBCSFRM_H
// x - skip<uint32>, X - skip<uint8>, s - char*, f - float, i - uint32, b - uint8, d - index (not included)
-// n - index (included), l - bool, p - field present in sql dbc, a - field absent in sql dbc
+// n - index (included), l - uint64, p - field present in sql dbc, a - field absent in sql dbc
-char const Achievementfmt[] = "niixsxiixixxiix";
+char const Achievementfmt[] = "niixsxiixixxiii";
const std::string CustomAchievementfmt = "pppaaaapapaapp";
const std::string CustomAchievementIndex = "ID";
-char const AchievementCriteriafmt[] = "niiiliiiisiiiiixxiiiiii";
char const AreaTableEntryfmt[] = "iiiniixxxxsxixiiiiixxxxxxxxxx";
char const AreaGroupEntryfmt[] = "niiiiiii";
char const AreaTriggerEntryfmt[] = "nifffxxxfffffxxxx";
@@ -49,6 +48,8 @@ char const CreatureFamilyfmt[] = "nfifiiiiixsx";
char const CreatureModelDatafmt[] = "nixxxxxxxxxxxxxffxxxxxxxxxxxxxxxxx";
char const CreatureSpellDatafmt[] = "niiiixxxx";
char const CreatureTypefmt[] = "nxx";
+char const Criteriafmt[] = "niiiiiiiixii";
+char const CriteriaTreefmt[] = "niliixxx";
char const CurrencyTypesfmt[] = "nixxxxxiiixx";
char const DestructibleModelDatafmt[] = "nixxxixxxxixxxxixxxxxxxx";
char const DungeonEncounterfmt[] = "niiixsxxx";
@@ -108,6 +109,7 @@ char const MapEntryfmt[] = "nxiixxsixxixiffxiiiixx";
char const MapDifficultyEntryfmt[] = "diisiixx";
char const MinorTalentEntryfmt[] = "niii";
char const MovieEntryfmt[] = "nxxxx";
+char const ModifierTreefmt[] = "niiiiii";
char const MountCapabilityfmt[] = "niiiiiii";
char const MountTypefmt[] = "niiiiiiiiiiiiiiiiiiiiiiii";
char const NameGenfmt[] = "dsii";
diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp
index 0bfa08d62c9..bd9b05e35bc 100644
--- a/src/server/game/Guilds/Guild.cpp
+++ b/src/server/game/Guilds/Guild.cpp
@@ -1550,17 +1550,19 @@ void Guild::HandleSetAchievementTracking(WorldSession* session, std::set<uint32>
{
std::set<uint32> criteriaIds;
+ /*
for (std::set<uint32>::iterator achievementId = achievementIds.begin(); achievementId != achievementIds.end(); ++achievementId)
{
if (AchievementCriteriaEntryList const* cList = sAchievementMgr->GetAchievementCriteriaByAchievement(*achievementId))
{
for (AchievementCriteriaEntryList::const_iterator itr = cList->begin(); itr != cList->end(); ++itr)
{
- AchievementCriteriaEntry const* criteria = *itr;
+ AchievementCriteriaTree const* criteria = *itr;
criteriaIds.insert(criteria->ID);
}
}
}
+ */
member->SetTrackedCriteriaIds(criteriaIds);
m_achievementMgr.SendAllTrackedCriterias(player, member->GetTrackedCriteriaIds());
@@ -2629,7 +2631,7 @@ void Guild::BroadcastPacketToRank(WorldPacket* packet, uint8 rankId) const
player->GetSession()->SendPacket(packet);
}
-void Guild::BroadcastPacket(WorldPacket* packet) const
+void Guild::BroadcastPacket(WorldPacket const* packet) const
{
for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr)
if (Player* player = itr->second->FindPlayer())
diff --git a/src/server/game/Guilds/Guild.h b/src/server/game/Guilds/Guild.h
index 4abeb282b0c..132ecc72f89 100644
--- a/src/server/game/Guilds/Guild.h
+++ b/src/server/game/Guilds/Guild.h
@@ -846,7 +846,7 @@ public:
void BroadcastToGuild(WorldSession* session, bool officerOnly, std::string const& msg, uint32 language = LANG_UNIVERSAL) const;
void BroadcastAddonToGuild(WorldSession* session, bool officerOnly, std::string const& msg, std::string const& prefix) const;
void BroadcastPacketToRank(WorldPacket* packet, uint8 rankId) const;
- void BroadcastPacket(WorldPacket* packet) const;
+ void BroadcastPacket(WorldPacket const* packet) const;
void BroadcastPacketIfTrackingAchievement(WorldPacket* packet, uint32 criteriaId) const;
void MassInviteToEvent(WorldSession* session, uint32 minLevel, uint32 maxLevel, uint32 minRank);
diff --git a/src/server/game/Server/Packets/AchievementPackets.cpp b/src/server/game/Server/Packets/AchievementPackets.cpp
new file mode 100644
index 00000000000..d471d87426c
--- /dev/null
+++ b/src/server/game/Server/Packets/AchievementPackets.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "AchievementPackets.h"
+
+WorldPacket const* WorldPackets::Achievement::AllAchievements::Write()
+{
+ _worldPacket << uint32(Earned.size());
+ _worldPacket << uint32(Progress.size());
+
+ for (EarnedAchievement const& earned : Earned)
+ {
+ _worldPacket << uint32(earned.Id);
+ _worldPacket.AppendPackedTime(earned.Date);
+ _worldPacket << earned.Owner;
+ _worldPacket << uint32(earned.VirtualRealmAddress);
+ _worldPacket << uint32(earned.NativeRealmAddress);
+ }
+
+ for (CriteriaProgress const& progress : Progress)
+ {
+ _worldPacket << uint32(progress.Id);
+ _worldPacket << uint64(progress.Quantity);
+ _worldPacket << progress.Player;
+ _worldPacket.AppendPackedTime(progress.Date);
+ _worldPacket << uint32(progress.TimeFromStart);
+ _worldPacket << uint32(progress.TimeFromCreate);
+ _worldPacket.WriteBits(progress.Flags, 4);
+ _worldPacket.FlushBits();
+ }
+
+ return &_worldPacket;
+}
+
+WorldPacket const* WorldPackets::Achievement::CriteriaUpdate::Write()
+{
+ _worldPacket << uint32(CriteriaID);
+ _worldPacket << uint64(Quantity);
+ _worldPacket << PlayerGUID;
+ _worldPacket << uint32(Flags);
+ _worldPacket.AppendPackedTime(CurrentTime);
+ _worldPacket << uint32(ElapsedTime);
+ _worldPacket << uint32(CreationTime);
+
+ return &_worldPacket;
+}
+
+WorldPacket const* WorldPackets::Achievement::AchievementEarned::Write()
+{
+ _worldPacket << Sender;
+ _worldPacket << Earner;
+ _worldPacket << uint32(AchievementID);
+ _worldPacket.AppendPackedTime(Time);
+ _worldPacket << uint32(EarnerNativeRealm);
+ _worldPacket << uint32(EarnerVirtualRealm);
+ _worldPacket.WriteBit(Initial);
+ _worldPacket.FlushBits();
+
+ return &_worldPacket;
+}
diff --git a/src/server/game/Server/Packets/AchievementPackets.h b/src/server/game/Server/Packets/AchievementPackets.h
new file mode 100644
index 00000000000..9d609372831
--- /dev/null
+++ b/src/server/game/Server/Packets/AchievementPackets.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef game_AchievementPackets_h__
+#define game_AchievementPackets_h__
+
+#include "ObjectGuid.h"
+#include "Packet.h"
+
+namespace WorldPackets
+{
+ namespace Achievement
+ {
+ struct EarnedAchievement
+ {
+ uint32 Id = 0;
+ time_t Date = time_t(0);
+ ObjectGuid Owner;
+ uint32 VirtualRealmAddress = 0;
+ uint32 NativeRealmAddress = 0;
+ };
+
+ struct CriteriaProgress
+ {
+ uint32 Id = 0;
+ uint64 Quantity = 0;
+ ObjectGuid Player;
+ uint32 Flags = 0;
+ time_t Date = time_t(0);
+ uint32 TimeFromStart = 0;
+ uint32 TimeFromCreate = 0;
+ };
+
+ class AllAchievements final : public ServerPacket
+ {
+ public:
+ AllAchievements() : ServerPacket(SMSG_ALL_ACHIEVEMENT_DATA) { }
+
+ WorldPacket const* Write() override;
+
+ std::vector<EarnedAchievement> Earned;
+ std::vector<CriteriaProgress> Progress;
+ };
+
+ class CriteriaUpdate final : public ServerPacket
+ {
+ public:
+ CriteriaUpdate() : ServerPacket(SMSG_CRITERIA_UPDATE, 4 + 8 + 16 + 4 + 4 + 4 + 4) { }
+
+ WorldPacket const* Write() override;
+
+ uint32 CriteriaID = 0;
+ uint64 Quantity = 0;
+ ObjectGuid PlayerGUID;
+ uint32 Flags = 0;
+ time_t CurrentTime = time_t(0);
+ uint32 ElapsedTime = 0;
+ uint32 CreationTime = 0;
+ };
+
+ class AchievementEarned final : public ServerPacket
+ {
+ public:
+ AchievementEarned() : ServerPacket(SMSG_ACHIEVEMENT_EARNED, 16 + 4 + 4 + 4 + 4 + 1 + 16) { }
+
+ WorldPacket const* Write() override;
+
+ ObjectGuid Earner;
+ uint32 EarnerNativeRealm = 0;
+ uint32 EarnerVirtualRealm = 0;
+ uint32 AchievementID = 0;
+ time_t Time = time_t(0);
+ bool Initial = false;
+ ObjectGuid Sender;
+ };
+ }
+}
+
+#endif // game_AchievementPackets_h__
diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp
index e18e5e984ac..603e55ff738 100644
--- a/src/server/game/Server/Protocol/Opcodes.cpp
+++ b/src/server/game/Server/Protocol/Opcodes.cpp
@@ -709,14 +709,14 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACCOUNT_RESTRICTED_WARNING, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACCOUNT_TOYS_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACHIEVEMENT_DELETED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACHIEVEMENT_EARNED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACHIEVEMENT_EARNED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACTION_BUTTONS, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACTIVATETAXIREPLY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ADDON_INFO, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ADD_RUNE_POWER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ADJUST_SPLINE_DURATION, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_AI_REACTION, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_ALL_ACHIEVEMENT_DATA, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_ALL_ACHIEVEMENT_DATA, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_AREA_SPIRIT_HEALER_TIME, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_AREA_TRIGGER_MESSAGE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_AREA_TRIGGER_MOVEMENT_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
@@ -867,7 +867,7 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CORPSE_RECLAIM_DELAY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CREATURE_QUERY_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CRITERIA_DELETED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_CRITERIA_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_CRITERIA_UPDATE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CROSSED_INEBRIATION_THRESHOLD, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CURRENCY_LOOT_REMOVED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CURRENCY_LOOT_RESTORED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
diff --git a/src/server/game/Server/Protocol/Opcodes.h b/src/server/game/Server/Protocol/Opcodes.h
index 68fd9c30d48..ddad78a527b 100644
--- a/src/server/game/Server/Protocol/Opcodes.h
+++ b/src/server/game/Server/Protocol/Opcodes.h
@@ -686,16 +686,16 @@ enum OpcodeServer : uint32
SMSG_ACCOUNT_RESTRICTED_WARNING = 0xBADD,
SMSG_ACCOUNT_TOYS_UPDATE = 0x0590,
SMSG_ACHIEVEMENT_DELETED = 0xBADD,
- SMSG_ACHIEVEMENT_EARNED = 0xBADD,
+ SMSG_ACHIEVEMENT_EARNED = 0x010E,
SMSG_ACTION_BUTTONS = 0x1D1F,
SMSG_ACTIVATETAXIREPLY = 0xBADD,
SMSG_ADDON_INFO = 0x1D9F,
SMSG_ADD_RUNE_POWER = 0xBADD,
SMSG_ADJUST_SPLINE_DURATION = 0x0104,
SMSG_AI_REACTION = 0x0BA1,
- SMSG_ALL_ACHIEVEMENT_DATA = 0xBADD,
- SMSG_ALL_ACHIEVEMENT_DATA_ACCOUNT = 0x0123,
- SMSG_ALL_ACHIEVEMENT_DATA_PLAYER = 0x0030,
+ SMSG_ACCOUNT_CRITERIA_UPDATE = 0x0912,
+ SMSG_ALL_ACCOUNT_CRITERIA = 0x0123,
+ SMSG_ALL_ACHIEVEMENT_DATA = 0x0030,
SMSG_AREA_SPIRIT_HEALER_TIME = 0xBADD,
SMSG_AREA_TRIGGER_MESSAGE = 0xBADD,
SMSG_AREA_TRIGGER_MOVEMENT_UPDATE = 0xBADD,
@@ -852,9 +852,7 @@ enum OpcodeServer : uint32
SMSG_CORPSE_RECLAIM_DELAY = 0x0BE2,
SMSG_CREATURE_QUERY_RESPONSE = 0x0A26,
SMSG_CRITERIA_DELETED = 0xBADD,
- SMSG_CRITERIA_UPDATE = 0xBADD,
- SMSG_CRITERIA_UPDATE_ACCOUNT = 0x0912,
- SMSG_CRITERIA_UPDATE_PLAYER = 0x1904,
+ SMSG_CRITERIA_UPDATE = 0x1904,
SMSG_CROSSED_INEBRIATION_THRESHOLD = 0xBADD,
SMSG_CURRENCY_LOOT_REMOVED = 0xBADD,
SMSG_CURRENCY_LOOT_RESTORED = 0xBADD,
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 5c8706da09c..7195c58ae00 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1693,6 +1693,8 @@ void World::SetInitialWorldSettings()
TC_LOG_INFO("server.loading", "Loading Achievements...");
sAchievementMgr->LoadAchievementReferenceList();
+ TC_LOG_INFO("server.loading", "Loading Achievement Criteria Modifier trees...");
+ sAchievementMgr->LoadAchievementCriteriaModifiersTree();
TC_LOG_INFO("server.loading", "Loading Achievement Criteria Lists...");
sAchievementMgr->LoadAchievementCriteriaList();
TC_LOG_INFO("server.loading", "Loading Achievement Criteria Data...");