diff options
Diffstat (limited to 'src')
82 files changed, 4010 insertions, 3890 deletions
diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h index 07ad2a2fd4b..2b85d922657 100644 --- a/src/server/game/Accounts/RBAC.h +++ b/src/server/game/Accounts/RBAC.h @@ -254,7 +254,7 @@ enum RBACPermissions RBAC_PERM_COMMAND_DESERTER_INSTANCE_REMOVE = 347, RBAC_PERM_COMMAND_DISABLE = 348, RBAC_PERM_COMMAND_DISABLE_ADD = 349, - RBAC_PERM_COMMAND_DISABLE_ADD_ACHIEVEMENT_CRITERIA = 350, + RBAC_PERM_COMMAND_DISABLE_ADD_CRITERIA = 350, RBAC_PERM_COMMAND_DISABLE_ADD_BATTLEGROUND = 351, RBAC_PERM_COMMAND_DISABLE_ADD_MAP = 352, RBAC_PERM_COMMAND_DISABLE_ADD_MMAP = 353, @@ -263,7 +263,7 @@ enum RBACPermissions RBAC_PERM_COMMAND_DISABLE_ADD_SPELL = 356, RBAC_PERM_COMMAND_DISABLE_ADD_VMAP = 357, RBAC_PERM_COMMAND_DISABLE_REMOVE = 358, - RBAC_PERM_COMMAND_DISABLE_REMOVE_ACHIEVEMENT_CRITERIA = 359, + RBAC_PERM_COMMAND_DISABLE_REMOVE_CRITERIA = 359, RBAC_PERM_COMMAND_DISABLE_REMOVE_BATTLEGROUND = 360, RBAC_PERM_COMMAND_DISABLE_REMOVE_MAP = 361, RBAC_PERM_COMMAND_DISABLE_REMOVE_MMAP = 362, @@ -513,7 +513,7 @@ enum RBACPermissions RBAC_PERM_COMMAND_QUEST_REWARD = 606, RBAC_PERM_COMMAND_RELOAD = 607, RBAC_PERM_COMMAND_RELOAD_ACCESS_REQUIREMENT = 608, - RBAC_PERM_COMMAND_RELOAD_ACHIEVEMENT_CRITERIA_DATA = 609, + RBAC_PERM_COMMAND_RELOAD_CRITERIA_DATA = 609, RBAC_PERM_COMMAND_RELOAD_ACHIEVEMENT_REWARD = 610, RBAC_PERM_COMMAND_RELOAD_ALL = 611, RBAC_PERM_COMMAND_RELOAD_ALL_ACHIEVEMENT = 612, diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index f15476d4071..642c21e3ff1 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -18,644 +18,221 @@ #include "AchievementMgr.h" #include "AchievementPackets.h" -#include "ArenaTeam.h" -#include "ArenaTeamMgr.h" -#include "Battleground.h" #include "CellImpl.h" #include "ChatTextBuilder.h" -#include "Common.h" -#include "DatabaseEnv.h" -#include "DBCEnums.h" -#include "DisableMgr.h" -#include "GameEventMgr.h" -#include "Garrison.h" #include "GridNotifiersImpl.h" #include "Group.h" -#include "Guild.h" #include "GuildMgr.h" -#include "InstanceScript.h" #include "Language.h" -#include "Map.h" -#include "MapManager.h" #include "ObjectMgr.h" -#include "Player.h" -#include "ReputationMgr.h" -#include "ScriptMgr.h" -#include "SpellMgr.h" -#include "World.h" -#include "WorldPacket.h" - -bool AchievementCriteriaData::IsValid(AchievementCriteria const* criteria) + +struct VisibleAchievementCheck { - if (dataType >= MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE) + AchievementEntry const* operator()(std::pair<uint32, CompletedAchievementData> const& val) { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` for criteria (Entry: %u) contains a wrong data type (%u), ignored.", criteria->ID, dataType); - return false; + AchievementEntry const* achievement = sAchievementStore.LookupEntry(val.first); + if (achievement && !(achievement->Flags & ACHIEVEMENT_FLAG_HIDDEN)) + return achievement; + return nullptr; } +}; - switch (criteria->Entry->Type) - { - case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE: - case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE: - case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG: - case ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING: - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST: // only hardcoded list - case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL: - case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA: - case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE: - case ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL: - case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL: - case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE: - case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2: - case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET: - case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2: - case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM: - case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT: - case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT: - case ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE: - case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL: - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST: // only Children's Week achievements - case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM: // only Children's Week achievements - case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS: - case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL: - case ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN: - break; - default: - if (dataType != ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT) - { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` contains data for a non-supported criteria type (Entry: %u Type: %u), ignored.", criteria->ID, criteria->Entry->Type); - return false; - } - break; - } +AchievementMgr::AchievementMgr() : _achievementPoints(0) { } - switch (dataType) - { - case ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE: - case ACHIEVEMENT_CRITERIA_DATA_TYPE_INSTANCE_SCRIPT: - return true; - case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_CREATURE: - 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) contains a non-existing creature id in value1 (%u), ignored.", - criteria->ID, criteria->Entry->Type, dataType, creature.id); - return false; - } - return true; - case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE: - 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->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) contains a non-existing class in value1 (%u), ignored.", - 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) contains a non-existing race in value2 (%u), ignored.", - criteria->ID, criteria->Entry->Type, dataType, classRace.race_id); - return false; - } - return true; - case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_LESS_HEALTH: - 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) contains a wrong percent value in value1 (%u), ignored.", - criteria->ID, criteria->Entry->Type, dataType, health.percent); - return false; - } - return true; - case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA: - case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA: - { - SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(aura.spell_id); - if (!spellEntry) - { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) contains a wrong spell id in value1 (%u), ignored.", - 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) contains a wrong spell effect index in value2 (%u), ignored.", - 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) contains a non-aura spell effect (ID: %u Effect: %u), ignored.", - 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; - } - case ACHIEVEMENT_CRITERIA_DATA_TYPE_VALUE: - 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) contains a wrong ComparisionType in value2 (%u), ignored.", - criteria->ID, criteria->Entry->Type, dataType, value.compType); - return false; - } - return true; - case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_LEVEL: - 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) contains a wrong minlevel in value1 (%u), ignored.", - criteria->ID, criteria->Entry->Type, dataType, level.minlevel); - return false; - } - return true; - case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_GENDER: - 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) contains a wrong gender value in value1 (%u), ignored.", - criteria->ID, criteria->Entry->Type, dataType, gender.gender); - return false; - } - return true; - case ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT: - 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 a ScriptName set, ignored.", - criteria->ID, criteria->Entry->Type, dataType); - return false; - } - return true; - case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT: - 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) contains a wrong max players count in value1 (%u), ignored.", - criteria->ID, criteria->Entry->Type, dataType, map_players.maxcount); - return false; - } - return true; - case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM: - 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) contains an unknown team value in value1 (%u), ignored.", - criteria->ID, criteria->Entry->Type, dataType, team.team); - return false; - } - return true; - case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_DRUNK: - 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) contains an unknown drunken state value in value1 (%u), ignored.", - criteria->ID, criteria->Entry->Type, dataType, drunk.state); - return false; - } - return true; - case ACHIEVEMENT_CRITERIA_DATA_TYPE_HOLIDAY: - 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) contains an unknown holiday entry in value1 (%u), ignored.", - criteria->ID, criteria->Entry->Type, dataType, holiday.id); - return false; - } - return true; - case ACHIEVEMENT_CRITERIA_DATA_TYPE_GAME_EVENT: - { - GameEventMgr::GameEventDataMap const& events = sGameEventMgr->GetEventMap(); - 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->Entry->Type, dataType, game_event.id); - return false; - } - return true; - } - case ACHIEVEMENT_CRITERIA_DATA_TYPE_BG_LOSS_TEAM_SCORE: - return true; // not check correctness node indexes - case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPED_ITEM: - 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) contains an unknown quality state value in value1 (%u), ignored.", - criteria->ID, criteria->Entry->Type, dataType, equipped_item.item_quality); - return false; - } - return true; - case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE: - 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) should not have 0 in either value field. Ignored.", - 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) contains a non-existing class entry in value1 (%u), ignored.", - 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) contains a non-existing race entry in value2 (%u), ignored.", - criteria->ID, criteria->Entry->Type, dataType, classRace.race_id); - return false; - } - return true; - case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_KNOWN_TITLE: - 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) contains an unknown title_id in value1 (%u), ignore.", - 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) contains data of a non-supported data type (%u), ignored.", criteria->ID, criteria->Entry->Type, dataType); - return false; - } -} +AchievementMgr::~AchievementMgr() { } -bool AchievementCriteriaData::Meets(uint32 criteria_id, Player const* source, Unit const* target, uint32 miscValue1 /*= 0*/) const +/** +* called at player login. The player might have fulfilled some achievements when the achievement system wasn't working yet +*/ +void AchievementMgr::CheckAllAchievementCriteria(Player* referencePlayer) { - switch (dataType) - { - case ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE: - return true; - case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_CREATURE: - if (!target || target->GetTypeId() != TYPEID_UNIT) - return false; - return target->GetEntry() == creature.id; - case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE: - if (!target || target->GetTypeId() != TYPEID_PLAYER) - return false; - if (classRace.class_id && classRace.class_id != target->ToPlayer()->getClass()) - return false; - if (classRace.race_id && classRace.race_id != target->ToPlayer()->getRace()) - return false; - return true; - case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE: - if (source->GetTypeId() != TYPEID_PLAYER) - return false; - if (classRace.class_id && classRace.class_id != source->ToPlayer()->getClass()) - return false; - if (classRace.race_id && classRace.race_id != source->ToPlayer()->getRace()) - return false; - return true; - case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_LESS_HEALTH: - if (!target || target->GetTypeId() != TYPEID_PLAYER) - return false; - return !target->HealthAbovePct(health.percent); - case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA: - return source->HasAuraEffect(aura.spell_id, aura.effect_idx); - case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA: - return target && target->HasAuraEffect(aura.spell_id, aura.effect_idx); - case ACHIEVEMENT_CRITERIA_DATA_TYPE_VALUE: - return CompareValues(ComparisionType(value.compType), miscValue1, value.value); - case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_LEVEL: - if (!target) - return false; - return target->getLevel() >= level.minlevel; - case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_GENDER: - if (!target) - return false; - return target->getGender() == gender.gender; - case ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT: - return sScriptMgr->OnCriteriaCheck(ScriptId, const_cast<Player*>(source), const_cast<Unit*>(target)); - case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT: - return source->GetMap()->GetPlayersCountExceptGMs() <= map_players.maxcount; - case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM: - if (!target || target->GetTypeId() != TYPEID_PLAYER) - return false; - return target->ToPlayer()->GetTeam() == team.team; - case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_DRUNK: - return Player::GetDrunkenstateByValue(source->GetDrunkValue()) >= DrunkenState(drunk.state); - case ACHIEVEMENT_CRITERIA_DATA_TYPE_HOLIDAY: - return IsHolidayActive(HolidayIds(holiday.id)); - case ACHIEVEMENT_CRITERIA_DATA_TYPE_GAME_EVENT: - return IsEventActive(game_event.id); - case ACHIEVEMENT_CRITERIA_DATA_TYPE_BG_LOSS_TEAM_SCORE: - { - Battleground* bg = source->GetBattleground(); - if (!bg) - return false; - - uint32 score = bg->GetTeamScore(source->GetTeamId() == TEAM_ALLIANCE ? TEAM_HORDE : TEAM_ALLIANCE); - return score >= bg_loss_team_score.min_score && score <= bg_loss_team_score.max_score; - } - case ACHIEVEMENT_CRITERIA_DATA_TYPE_INSTANCE_SCRIPT: - { - if (!source->IsInWorld()) - return false; - Map* map = source->GetMap(); - if (!map->IsDungeon()) - { - TC_LOG_ERROR("achievement", "Achievement system call ACHIEVEMENT_CRITERIA_DATA_TYPE_INSTANCE_SCRIPT (%u) for achievement criteria %u in a non-dungeon/non-raid map %u", - dataType, criteria_id, map->GetId()); - return false; - } - InstanceScript* instance = map->ToInstanceMap()->GetInstanceScript(); - if (!instance) - { - TC_LOG_ERROR("achievement", "Achievement system call ACHIEVEMENT_CRITERIA_DATA_TYPE_INSTANCE_SCRIPT (%u) for achievement criteria %u in map %u, but the map does not have an instance script.", - dataType, criteria_id, map->GetId()); - return false; - } - return instance->CheckAchievementCriteriaMeet(criteria_id, source, target, miscValue1); - } - case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPED_ITEM: - { - ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(miscValue1); - if (!pProto) - return false; - return pProto->GetBaseItemLevel() >= equipped_item.item_level && pProto->GetQuality() >= equipped_item.item_quality; - } - case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_ID: - return source->GetMapId() == map_id.mapId; - case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_KNOWN_TITLE: - { - if (CharTitlesEntry const* titleInfo = sCharTitlesStore.LookupEntry(known_title.title_id)) - return source && source->HasTitle(titleInfo->MaskID); - - return false; - } - default: - break; - } - return false; + // suppress sending packets + for (uint32 i = 0; i < CRITERIA_TYPE_TOTAL; ++i) + UpdateCriteria(CriteriaTypes(i), 0, 0, 0, NULL, referencePlayer); } -bool AchievementCriteriaDataSet::Meets(Player const* source, Unit const* target, uint32 miscValue /*= 0*/) const +bool AchievementMgr::HasAchieved(uint32 achievementId) const { - for (AchievementCriteriaData const& data : storage) - if (!data.Meets(criteria_id, source, target, miscValue)) - return false; - - return true; + return _completedAchievements.find(achievementId) != _completedAchievements.end(); } -template<class T> -AchievementMgr<T>::AchievementMgr(T* owner): _owner(owner), _achievementPoints(0) { } - -template<class T> -AchievementMgr<T>::~AchievementMgr() { } - -template<class T> -void AchievementMgr<T>::SendPacket(WorldPacket const* /*data*/) const { } - -template<> -void AchievementMgr<Guild>::SendPacket(WorldPacket const* data) const +uint32 AchievementMgr::GetAchievementPoints() const { - GetOwner()->BroadcastPacket(data); + return _achievementPoints; } -template<> -void AchievementMgr<Player>::SendPacket(WorldPacket const* data) const +bool AchievementMgr::CanUpdateCriteriaTree(Criteria const* criteria, CriteriaTree const* tree, Player* referencePlayer) const { - GetOwner()->GetSession()->SendPacket(data); + if (HasAchieved(tree->Achievement->ID)) + { + TC_LOG_TRACE("criteria.achievement", "AchievementMgr::CanUpdateCriteriaTree: (Id: %u Type %s Achievement %u) Achievement already earned", + criteria->ID, CriteriaMgr::GetCriteriaTypeString(criteria->Entry->Type), tree->Achievement->ID); + return false; + } + + if (tree->Achievement->MapID != -1 && referencePlayer->GetMapId() != uint32(tree->Achievement->MapID)) + { + TC_LOG_TRACE("criteria.achievement", "AchievementMgr::CanUpdateCriteriaTree: (Id: %u Type %s Achievement %u) Wrong map", + criteria->ID, CriteriaMgr::GetCriteriaTypeString(criteria->Entry->Type), tree->Achievement->ID); + return false; + } + + if ((tree->Achievement->Faction == ACHIEVEMENT_FACTION_HORDE && referencePlayer->GetTeam() != HORDE) || + (tree->Achievement->Faction == ACHIEVEMENT_FACTION_ALLIANCE && referencePlayer->GetTeam() != ALLIANCE)) + { + TC_LOG_TRACE("criteria.achievement", "AchievementMgr::CanUpdateCriteriaTree: (Id: %u Type %s Achievement %u) Wrong faction", + criteria->ID, CriteriaMgr::GetCriteriaTypeString(criteria->Entry->Type), tree->Achievement->ID); + return false; + } + + return true; } -template<class T> -void AchievementMgr<T>::RemoveCriteriaProgress(AchievementCriteria const* entry) +bool AchievementMgr::CanCompleteCriteriaTree(CriteriaTree const* tree) { - if (!entry) - return; + AchievementEntry const* achievement = tree->Achievement; + if (!achievement) + return false; - CriteriaProgressMap::iterator criteriaProgress = m_criteriaProgress.find(entry->ID); - if (criteriaProgress == m_criteriaProgress.end()) - return; + // counter can never complete + if (achievement->Flags & ACHIEVEMENT_FLAG_COUNTER) + return false; - WorldPackets::Achievement::CriteriaDeleted criteriaDeleted; - criteriaDeleted.CriteriaID = entry->ID; - SendPacket(criteriaDeleted.Write()); + if (achievement->Flags & (ACHIEVEMENT_FLAG_REALM_FIRST_REACH | ACHIEVEMENT_FLAG_REALM_FIRST_KILL)) + { + // someone on this realm has already completed that achievement + if (sAchievementMgr->IsRealmCompleted(achievement)) + return false; + } - m_criteriaProgress.erase(criteriaProgress); + return true; } -template<> -void AchievementMgr<Guild>::RemoveCriteriaProgress(AchievementCriteria const* entry) +void AchievementMgr::CompletedCriteriaTree(CriteriaTree const* tree, Player* referencePlayer) { - if (!entry) + // counter can never complete + if (tree->Achievement->Flags & ACHIEVEMENT_FLAG_COUNTER) return; - CriteriaProgressMap::iterator criteriaProgress = m_criteriaProgress.find(entry->ID); - if (criteriaProgress == m_criteriaProgress.end()) + // already completed and stored + if (HasAchieved(tree->Achievement->ID)) return; - WorldPackets::Achievement::GuildCriteriaDeleted guildCriteriaDeleted; - guildCriteriaDeleted.GuildGUID = GetOwner()->GetGUID(); - guildCriteriaDeleted.CriteriaID = entry->ID; - SendPacket(guildCriteriaDeleted.Write()); + if (IsCompletedAchievement(tree->Achievement)) + CompletedAchievement(tree->Achievement, referencePlayer); +} + +void AchievementMgr::AfterCriteriaTreeUpdate(CriteriaTree const* tree, Player* 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); - m_criteriaProgress.erase(criteriaProgress); + if (std::vector<AchievementEntry const*> const* achRefList = sAchievementMgr->GetAchievementByReferencedId(tree->Achievement->ID)) + for (AchievementEntry const* refAchievement : *achRefList) + if (IsCompletedAchievement(refAchievement)) + CompletedAchievement(refAchievement, referencePlayer); } -template<class T> -void AchievementMgr<T>::ResetAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1, uint64 miscValue2, bool evenIfCriteriaComplete) +bool AchievementMgr::IsCompletedAchievement(AchievementEntry const* entry) { - TC_LOG_DEBUG("achievement", "ResetAchievementCriteria(%u, " UI64FMTD ", " UI64FMTD ")", type, miscValue1, miscValue2); + // counter can never complete + if (entry->Flags & ACHIEVEMENT_FLAG_COUNTER) + return false; - // disable for gamemasters with GM-mode enabled - if (GetOwner()->IsGameMaster()) - return; + CriteriaTree const* tree = sCriteriaMgr->GetCriteriaTree(entry->CriteriaTree); + if (!tree) + return false; - AchievementCriteriaList const& achievementCriteriaList = sAchievementMgr->GetAchievementCriteriaByType(type); - for (AchievementCriteria const* achievementCriteria : achievementCriteriaList) + // 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) { - if (achievementCriteria->Entry->FailEvent != miscValue1 || (achievementCriteria->Entry->FailAsset && achievementCriteria->Entry->FailAsset != miscValue2)) - continue; - - AchievementCriteriaTreeList const* trees = sAchievementMgr->GetAchievementCriteriaTreesByCriteria(achievementCriteria->ID); - bool allComplete = true; - for (AchievementCriteriaTree const* tree : *trees) + uint64 progress = 0; + CriteriaMgr::WalkCriteriaTree(tree, [this, &progress](CriteriaTree const* criteriaTree) { - // don't update already completed criteria if not forced or achievement already complete - if (!(IsCompletedCriteriaTree(tree) && !evenIfCriteriaComplete) || !HasAchieved(tree->Achievement->ID)) - { - allComplete = false; - break; - } - } + if (criteriaTree->Criteria) + if (CriteriaProgress const* criteriaProgress = this->GetCriteriaProgress(criteriaTree->Criteria)) + progress += criteriaProgress->Counter; + }); + return progress >= tree->Entry->Amount; + } - if (allComplete) - continue; + return IsCompletedCriteriaTree(tree); +} - RemoveCriteriaProgress(achievementCriteria); - } +bool AchievementMgr::RequiredAchievementSatisfied(uint32 achievementId) const +{ + return HasAchieved(achievementId); } -template<> -void AchievementMgr<Guild>::ResetAchievementCriteria(AchievementCriteriaTypes /*type*/, uint64 /*miscValue1*/, uint64 /*miscValue2*/, bool /*evenIfCriteriaComplete*/) +PlayerAchievementMgr::PlayerAchievementMgr(Player* owner) : _owner(owner) { - // Not needed } -void DeletePlayerAchievementsFromDB(ObjectGuid guid) +void PlayerAchievementMgr::Reset() { - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + AchievementMgr::Reset(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACHIEVEMENT); - stmt->setUInt64(0, guid.GetCounter()); - trans->Append(stmt); + for (auto iter = _completedAchievements.begin(); iter != _completedAchievements.end(); ++iter) + { + WorldPackets::Achievement::AchievementDeleted achievementDeleted; + achievementDeleted.AchievementID = iter->first; + SendPacket(achievementDeleted.Write()); + } - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACHIEVEMENT_PROGRESS); - stmt->setUInt64(0, guid.GetCounter()); - trans->Append(stmt); + _completedAchievements.clear(); + _achievementPoints = 0; + DeleteFromDB(_owner->GetGUID()); - CharacterDatabase.CommitTransaction(trans); + // re-fill data + CheckAllAchievementCriteria(_owner); } -void DeleteGuildAchievementsFromDB(ObjectGuid guid) +void PlayerAchievementMgr::DeleteFromDB(ObjectGuid const& guid) { SQLTransaction trans = CharacterDatabase.BeginTransaction(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GUILD_ACHIEVEMENTS); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACHIEVEMENT); stmt->setUInt64(0, guid.GetCounter()); trans->Append(stmt); - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GUILD_ACHIEVEMENT_CRITERIA); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACHIEVEMENT_PROGRESS); stmt->setUInt64(0, guid.GetCounter()); trans->Append(stmt); CharacterDatabase.CommitTransaction(trans); } -template<class T> -void AchievementMgr<T>::SaveToDB(SQLTransaction& /*trans*/) -{ -} - -template<> -void AchievementMgr<Player>::SaveToDB(SQLTransaction& trans) -{ - if (!m_completedAchievements.empty()) - { - for (CompletedAchievementMap::iterator iter = m_completedAchievements.begin(); iter != m_completedAchievements.end(); ++iter) - { - if (!iter->second.changed) - continue; - - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACHIEVEMENT_BY_ACHIEVEMENT); - stmt->setUInt16(0, iter->first); - stmt->setUInt64(1, GetOwner()->GetGUID().GetCounter()); - trans->Append(stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_ACHIEVEMENT); - stmt->setUInt64(0, GetOwner()->GetGUID().GetCounter()); - stmt->setUInt16(1, iter->first); - stmt->setUInt32(2, uint32(iter->second.date)); - trans->Append(stmt); - - iter->second.changed = false; - } - } - - if (!m_criteriaProgress.empty()) - { - for (CriteriaProgressMap::iterator iter = m_criteriaProgress.begin(); iter != m_criteriaProgress.end(); ++iter) - { - if (!iter->second.changed) - continue; - - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACHIEVEMENT_PROGRESS_BY_CRITERIA); - stmt->setUInt64(0, GetOwner()->GetGUID().GetCounter()); - stmt->setUInt32(1, iter->first); - trans->Append(stmt); - - if (iter->second.counter) - { - stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_ACHIEVEMENT_PROGRESS); - stmt->setUInt64(0, GetOwner()->GetGUID().GetCounter()); - stmt->setUInt32(1, iter->first); - stmt->setUInt32(2, iter->second.counter); - stmt->setUInt32(3, uint32(iter->second.date)); - trans->Append(stmt); - } - - iter->second.changed = false; - } - } -} - -template<> -void AchievementMgr<Guild>::SaveToDB(SQLTransaction& trans) -{ - PreparedStatement* stmt; - std::ostringstream guidstr; - for (CompletedAchievementMap::const_iterator itr = m_completedAchievements.begin(); itr != m_completedAchievements.end(); ++itr) - { - if (!itr->second.changed) - continue; - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_ACHIEVEMENT); - stmt->setUInt64(0, GetOwner()->GetId()); - stmt->setUInt16(1, itr->first); - trans->Append(stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_ACHIEVEMENT); - stmt->setUInt64(0, GetOwner()->GetId()); - stmt->setUInt16(1, itr->first); - stmt->setUInt32(2, itr->second.date); - for (GuidSet::const_iterator gItr = itr->second.guids.begin(); gItr != itr->second.guids.end(); ++gItr) - guidstr << gItr->GetCounter() << ','; - - stmt->setString(3, guidstr.str()); - trans->Append(stmt); - - guidstr.str(""); - } - - for (CriteriaProgressMap::const_iterator itr = m_criteriaProgress.begin(); itr != m_criteriaProgress.end(); ++itr) - { - if (!itr->second.changed) - continue; - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_ACHIEVEMENT_CRITERIA); - stmt->setUInt64(0, GetOwner()->GetId()); - stmt->setUInt32(1, itr->first); - trans->Append(stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_ACHIEVEMENT_CRITERIA); - stmt->setUInt64(0, GetOwner()->GetId()); - stmt->setUInt32(1, itr->first); - stmt->setUInt64(2, itr->second.counter); - stmt->setUInt32(3, itr->second.date); - stmt->setUInt64(4, itr->second.PlayerGUID.GetCounter()); - trans->Append(stmt); - } -} -template<class T> -void AchievementMgr<T>::LoadFromDB(PreparedQueryResult /*achievementResult*/, PreparedQueryResult /*criteriaResult*/) -{ -} - -template<> -void AchievementMgr<Player>::LoadFromDB(PreparedQueryResult achievementResult, PreparedQueryResult criteriaResult) +void PlayerAchievementMgr::LoadFromDB(PreparedQueryResult achievementResult, PreparedQueryResult criteriaResult) { if (achievementResult) { do { Field* fields = achievementResult->Fetch(); - uint32 achievementid = fields[0].GetUInt16(); + uint32 achievementid = fields[0].GetUInt32(); // must not happen: cleanup at server startup in sAchievementMgr->LoadCompletedAchievements() - AchievementEntry const* achievement = sAchievementMgr->GetAchievement(achievementid); + AchievementEntry const* achievement = sAchievementStore.LookupEntry(achievementid); if (!achievement) continue; - CompletedAchievementData& ca = m_completedAchievements[achievementid]; - ca.date = time_t(fields[1].GetUInt32()); - ca.changed = false; + CompletedAchievementData& ca = _completedAchievements[achievementid]; + ca.Date = time_t(fields[1].GetUInt32()); + ca.Changed = false; _achievementPoints += achievement->Points; // title achievement rewards are retroactive if (AchievementReward const* reward = sAchievementMgr->GetAchievementReward(achievement)) - if (uint32 titleId = reward->titleId[Player::TeamForRace(GetOwner()->getRace()) == ALLIANCE ? 0 : 1]) + if (uint32 titleId = reward->TitleId[Player::TeamForRace(_owner->getRace()) == ALLIANCE ? 0 : 1]) if (CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(titleId)) - GetOwner()->SetTitle(titleEntry); + _owner->SetTitle(titleEntry); - } - while (achievementResult->NextRow()); + } while (achievementResult->NextRow()); } if (criteriaResult) @@ -664,15 +241,15 @@ void AchievementMgr<Player>::LoadFromDB(PreparedQueryResult achievementResult, P do { Field* fields = criteriaResult->Fetch(); - uint32 id = fields[0].GetUInt32(); + uint32 id = fields[0].GetUInt32(); uint64 counter = fields[1].GetUInt64(); - time_t date = time_t(fields[2].GetUInt32()); + time_t date = time_t(fields[2].GetUInt32()); - AchievementCriteria const* criteria = sAchievementMgr->GetAchievementCriteria(id); + Criteria const* criteria = sCriteriaMgr->GetCriteria(id); if (!criteria) { // Removing non-existing criteria data for all characters - TC_LOG_ERROR("achievement", "Non-existing achievement criteria %u data has been removed from the table `character_achievement_progress`.", id); + TC_LOG_ERROR("criteria.achievement", "Non-existing achievement criteria %u data has been removed from the table `character_achievement_progress`.", id); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_ACHIEV_PROGRESS_CRITERIA); stmt->setUInt32(0, uint16(id)); @@ -684,1052 +261,183 @@ void AchievementMgr<Player>::LoadFromDB(PreparedQueryResult achievementResult, P if (criteria->Entry->StartTimer && time_t(date + criteria->Entry->StartTimer) < now) continue; - CriteriaProgress& progress = m_criteriaProgress[id]; - progress.counter = counter; - progress.date = date; - progress.changed = false; - } - while (criteriaResult->NextRow()); + CriteriaProgress& progress = _criteriaProgress[id]; + progress.Counter = counter; + progress.Date = date; + progress.Changed = false; + } while (criteriaResult->NextRow()); } } -template<> -void AchievementMgr<Guild>::LoadFromDB(PreparedQueryResult achievementResult, PreparedQueryResult criteriaResult) +void PlayerAchievementMgr::SaveToDB(SQLTransaction& trans) { - if (achievementResult) + if (!_completedAchievements.empty()) { - do + for (auto iter = _completedAchievements.begin(); iter != _completedAchievements.end(); ++iter) { - Field* fields = achievementResult->Fetch(); - uint32 achievementid = fields[0].GetUInt16(); - - // must not happen: cleanup at server startup in sAchievementMgr->LoadCompletedAchievements() - AchievementEntry const* achievement = sAchievementMgr->GetAchievement(achievementid); - if (!achievement) + if (!iter->second.Changed) continue; - CompletedAchievementData& ca = m_completedAchievements[achievementid]; - ca.date = time_t(fields[1].GetUInt32()); - Tokenizer guids(fields[2].GetString(), ' '); - for (uint32 i = 0; i < guids.size(); ++i) - ca.guids.insert(ObjectGuid::Create<HighGuid::Player>(uint64(strtoull(guids[i], nullptr, 10)))); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACHIEVEMENT_BY_ACHIEVEMENT); + stmt->setUInt32(0, iter->first); + stmt->setUInt64(1, _owner->GetGUID().GetCounter()); + trans->Append(stmt); - ca.changed = false; + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_ACHIEVEMENT); + stmt->setUInt64(0, _owner->GetGUID().GetCounter()); + stmt->setUInt32(1, iter->first); + stmt->setUInt32(2, uint32(iter->second.Date)); + trans->Append(stmt); - _achievementPoints += achievement->Points; + iter->second.Changed = false; } - while (achievementResult->NextRow()); } - if (criteriaResult) + if (!_criteriaProgress.empty()) { - time_t now = time(NULL); - do + for (auto iter = _criteriaProgress.begin(); iter != _criteriaProgress.end(); ++iter) { - Field* fields = criteriaResult->Fetch(); - uint32 id = fields[0].GetUInt32(); - uint64 counter = fields[1].GetUInt64(); - time_t date = time_t(fields[2].GetUInt32()); - ObjectGuid::LowType guid = fields[3].GetUInt64(); - - AchievementCriteria const* criteria = sAchievementMgr->GetAchievementCriteria(id); - if (!criteria) - { - // we will remove not existed criteria for all guilds - TC_LOG_ERROR("achievement", "Non-existing achievement criteria %u data removed from table `guild_achievement_progress`.", id); - - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_ACHIEV_PROGRESS_CRITERIA_GUILD); - stmt->setUInt32(0, uint16(id)); - CharacterDatabase.Execute(stmt); - continue; - } - - if (criteria->Entry->StartTimer && time_t(date + criteria->Entry->StartTimer) < now) + if (!iter->second.Changed) continue; - CriteriaProgress& progress = m_criteriaProgress[id]; - progress.counter = counter; - progress.date = date; - progress.PlayerGUID = ObjectGuid::Create<HighGuid::Player>(guid); - progress.changed = false; - } while (criteriaResult->NextRow()); - } -} - -template<class T> -void AchievementMgr<T>::Reset() -{ -} - -template<> -void AchievementMgr<Player>::Reset() -{ - for (CompletedAchievementMap::const_iterator iter = m_completedAchievements.begin(); iter != m_completedAchievements.end(); ++iter) - { - WorldPackets::Achievement::AchievementDeleted achievementDeleted; - achievementDeleted.AchievementID = iter->first; - SendPacket(achievementDeleted.Write()); - } - - for (CriteriaProgressMap::const_iterator iter = m_criteriaProgress.begin(); iter != m_criteriaProgress.end(); ++iter) - { - WorldPackets::Achievement::CriteriaDeleted criteriaDeleted; - criteriaDeleted.CriteriaID = iter->first; - SendPacket(criteriaDeleted.Write()); - } - - m_completedAchievements.clear(); - _achievementPoints = 0; - m_criteriaProgress.clear(); - DeleteFromDB(GetOwner()->GetGUID()); - - // re-fill data - CheckAllAchievementCriteria(GetOwner()); -} - -template<> -void AchievementMgr<Guild>::Reset() -{ - ObjectGuid guid = GetOwner()->GetGUID(); - for (CompletedAchievementMap::const_iterator iter = m_completedAchievements.begin(); iter != m_completedAchievements.end(); ++iter) - { - WorldPackets::Achievement::GuildAchievementDeleted guildAchievementDeleted; - guildAchievementDeleted.AchievementID = iter->first; - guildAchievementDeleted.GuildGUID = guid; - guildAchievementDeleted.TimeDeleted = time(NULL); - SendPacket(guildAchievementDeleted.Write()); - } - - while (!m_criteriaProgress.empty()) - if (AchievementCriteria const* criteria = sAchievementMgr->GetAchievementCriteria(m_criteriaProgress.begin()->first)) - RemoveCriteriaProgress(criteria); - - _achievementPoints = 0; - m_completedAchievements.clear(); - DeleteFromDB(GetOwner()->GetGUID()); -} - -template<class T> -void AchievementMgr<T>::SendAchievementEarned(AchievementEntry const* achievement) const -{ - // Don't send for achievements with ACHIEVEMENT_FLAG_HIDDEN - if (achievement->Flags & ACHIEVEMENT_FLAG_HIDDEN) - return; - - TC_LOG_DEBUG("achievement", "AchievementMgr::SendAchievementEarned(%u)", achievement->ID); - - if (Guild* guild = sGuildMgr->GetGuildById(GetOwner()->GetGuildId())) - { - Trinity::BroadcastTextBuilder _builder(GetOwner(), CHAT_MSG_GUILD_ACHIEVEMENT, BROADCAST_TEXT_ACHIEVEMENT_EARNED, GetOwner(), achievement->ID); - Trinity::LocalizedPacketDo<Trinity::BroadcastTextBuilder> _localizer(_builder); - guild->BroadcastWorker(_localizer, GetOwner()); - } - - if (achievement->Flags & (ACHIEVEMENT_FLAG_REALM_FIRST_KILL | ACHIEVEMENT_FLAG_REALM_FIRST_REACH)) - { - // broadcast realm first reached - WorldPackets::Achievement::ServerFirstAchievement serverFirstAchievement; - serverFirstAchievement.Name = GetOwner()->GetName(); - serverFirstAchievement.PlayerGUID = GetOwner()->GetGUID(); - serverFirstAchievement.AchievementID = achievement->ID; - sWorld->SendGlobalMessage(serverFirstAchievement.Write()); - } - // if player is in world he can tell his friends about new achievement - else if (GetOwner()->IsInWorld()) - { - Trinity::BroadcastTextBuilder _builder(GetOwner(), CHAT_MSG_ACHIEVEMENT, BROADCAST_TEXT_ACHIEVEMENT_EARNED, GetOwner(), achievement->ID); - Trinity::LocalizedPacketDo<Trinity::BroadcastTextBuilder> _localizer(_builder); - Trinity::PlayerDistWorker<Trinity::LocalizedPacketDo<Trinity::BroadcastTextBuilder> > _worker(GetOwner(), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), _localizer); - GetOwner()->VisitNearbyWorldObject(sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), _worker); - } - - 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<> -void AchievementMgr<Guild>::SendAchievementEarned(AchievementEntry const* achievement) const -{ - if (achievement->Flags & (ACHIEVEMENT_FLAG_REALM_FIRST_KILL | ACHIEVEMENT_FLAG_REALM_FIRST_REACH)) - { - // broadcast realm first reached - WorldPackets::Achievement::ServerFirstAchievement serverFirstAchievement; - serverFirstAchievement.Name = GetOwner()->GetName(); - serverFirstAchievement.PlayerGUID = GetOwner()->GetGUID(); - serverFirstAchievement.AchievementID = achievement->ID; - serverFirstAchievement.GuildAchievement = true; - sWorld->SendGlobalMessage(serverFirstAchievement.Write()); - } - - WorldPackets::Achievement::GuildAchievementEarned guildAchievementEarned; - guildAchievementEarned.AchievementID = achievement->ID; - guildAchievementEarned.GuildGUID = GetOwner()->GetGUID(); - guildAchievementEarned.TimeEarned = time(NULL); - SendPacket(guildAchievementEarned.Write()); -} - -template<class T> -void AchievementMgr<T>::SendCriteriaUpdate(AchievementCriteria const* /*criteria*/, CriteriaProgress const* /*progress*/, uint32 /*timeElapsed*/, bool /*timedCompleted*/) const -{ -} - -template<> -void AchievementMgr<Player>::SendCriteriaUpdate(AchievementCriteria const* criteria, CriteriaProgress const* progress, uint32 timeElapsed, bool timedCompleted) const -{ - WorldPackets::Achievement::CriteriaUpdate criteriaUpdate; - - 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 - - criteriaUpdate.Flags = 0; - criteriaUpdate.CurrentTime = progress->date; - criteriaUpdate.ElapsedTime = timeElapsed; - criteriaUpdate.CreationTime = 0; - - SendPacket(criteriaUpdate.Write()); -} - -template<> -void AchievementMgr<Guild>::SendCriteriaUpdate(AchievementCriteria const* entry, CriteriaProgress const* progress, uint32 /*timeElapsed*/, bool /*timedCompleted*/) const -{ - WorldPackets::Achievement::GuildCriteriaUpdate guildCriteriaUpdate; - guildCriteriaUpdate.Progress.resize(1); - - WorldPackets::Achievement::GuildCriteriaProgress& guildCriteriaProgress = guildCriteriaUpdate.Progress[0]; - guildCriteriaProgress.CriteriaID = entry->ID; - guildCriteriaProgress.DateCreated = 0; - guildCriteriaProgress.DateStarted = 0; - guildCriteriaProgress.DateUpdated = progress->date; - guildCriteriaProgress.Quantity = progress->counter; - guildCriteriaProgress.PlayerGUID = progress->PlayerGUID; - guildCriteriaProgress.Flags = 0; - - GetOwner()->BroadcastPacketIfTrackingAchievement(guildCriteriaUpdate.Write(), entry->ID); -} - -template<class T> -void AchievementMgr<T>::SendAllTrackedCriterias(Player* /*receiver*/, std::set<uint32> const& /*trackedCriterias*/) const -{ -} - -template<> -void AchievementMgr<Guild>::SendAllTrackedCriterias(Player* receiver, std::set<uint32> const& trackedCriterias) const -{ - WorldPackets::Achievement::GuildCriteriaUpdate guildCriteriaUpdate; - guildCriteriaUpdate.Progress.reserve(trackedCriterias.size()); - - for (uint32 criteriaId : trackedCriterias) - { - auto progress = m_criteriaProgress.find(criteriaId); - if (progress == m_criteriaProgress.end()) - continue; + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACHIEVEMENT_PROGRESS_BY_CRITERIA); + stmt->setUInt64(0, _owner->GetGUID().GetCounter()); + stmt->setUInt32(1, iter->first); + trans->Append(stmt); - WorldPackets::Achievement::GuildCriteriaProgress guildCriteriaProgress; - guildCriteriaProgress.CriteriaID = criteriaId; - guildCriteriaProgress.DateCreated = 0; - guildCriteriaProgress.DateStarted = 0; - guildCriteriaProgress.DateUpdated = progress->second.date; - guildCriteriaProgress.Quantity = progress->second.counter; - guildCriteriaProgress.PlayerGUID = progress->second.PlayerGUID; - guildCriteriaProgress.Flags = 0; + if (iter->second.Counter) + { + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_ACHIEVEMENT_PROGRESS); + stmt->setUInt64(0, _owner->GetGUID().GetCounter()); + stmt->setUInt32(1, iter->first); + stmt->setUInt64(2, iter->second.Counter); + stmt->setUInt32(3, uint32(iter->second.Date)); + trans->Append(stmt); + } - guildCriteriaUpdate.Progress.push_back(guildCriteriaProgress); + iter->second.Changed = false; + } } - - receiver->GetSession()->SendPacket(guildCriteriaUpdate.Write()); } -/** - * called at player login. The player might have fulfilled some achievements when the achievement system wasn't working yet - */ -template<class T> -void AchievementMgr<T>::CheckAllAchievementCriteria(Player* referencePlayer) +void PlayerAchievementMgr::ResetCriteria(CriteriaTypes type, uint64 miscValue1, uint64 miscValue2, bool evenIfCriteriaComplete) { - // suppress sending packets - for (uint32 i = 0; i < ACHIEVEMENT_CRITERIA_TYPE_TOTAL; ++i) - UpdateAchievementCriteria(AchievementCriteriaTypes(i), 0, 0, 0, NULL, referencePlayer); -} - -// 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; } - -/** - * this function will be called whenever the user might have done a criteria relevant action - */ -template<class T> -void AchievementMgr<T>::UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1 /*= 0*/, uint64 miscValue2 /*= 0*/, uint64 miscValue3 /*= 0*/, Unit const* unit /*= NULL*/, Player* referencePlayer /*= NULL*/) -{ - if (type >= ACHIEVEMENT_CRITERIA_TYPE_TOTAL) - { - TC_LOG_DEBUG("achievement", "UpdateAchievementCriteria: Wrong criteria type %u", type); - return; - } - - if (!referencePlayer) - { - TC_LOG_DEBUG("achievement", "UpdateAchievementCriteria: Player is NULL! Cant update criteria"); - return; - } + TC_LOG_DEBUG("criteria.achievement", "PlayerAchievementMgr::ResetCriteria(%u, " UI64FMTD ", " UI64FMTD ")", type, miscValue1, miscValue2); // disable for gamemasters with GM-mode enabled - if (referencePlayer->IsGameMaster()) - { - TC_LOG_DEBUG("achievement", "UpdateAchievementCriteria: [Player %s GM mode on] %s, %s (%u), " UI64FMTD ", " UI64FMTD ", " UI64FMTD - , referencePlayer->GetName().c_str(), GetOwner()->GetGUID().ToString().c_str(), AchievementGlobalMgr::GetCriteriaTypeString(type), type, miscValue1, miscValue2, miscValue3); + if (_owner->IsGameMaster()) return; - } - - TC_LOG_DEBUG("achievement", "UpdateAchievementCriteria: %s, %s (%u), " UI64FMTD ", " UI64FMTD ", " UI64FMTD - , GetOwner()->GetGUID().ToString().c_str(), AchievementGlobalMgr::GetCriteriaTypeString(type), type, miscValue1, miscValue2, miscValue3); - - // Lua_GetGuildLevelEnabled() is checked in achievement UI to display guild tab - //if (IsGuild<T>() && !sWorld->getBoolConfig(CONFIG_GUILD_LEVELING_ENABLED)) - // return; - AchievementCriteriaList const& achievementCriteriaList = sAchievementMgr->GetAchievementCriteriaByType(type, IsGuild<T>()); - for (AchievementCriteria const* achievementCriteria : achievementCriteriaList) + CriteriaList const& achievementCriteriaList = GetCriteriaByType(type); + for (Criteria const* achievementCriteria : achievementCriteriaList) { - AchievementCriteriaTreeList const* trees = sAchievementMgr->GetAchievementCriteriaTreesByCriteria(achievementCriteria->ID); - - if (!CanUpdateCriteria(achievementCriteria, trees, miscValue1, miscValue2, miscValue3, unit, referencePlayer)) + if (achievementCriteria->Entry->FailEvent != miscValue1 || (achievementCriteria->Entry->FailAsset && achievementCriteria->Entry->FailAsset != miscValue2)) continue; - // requirements not found in the dbc - if (AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria)) - if (!data->Meets(referencePlayer, unit, miscValue1)) - continue; - - switch (type) + std::vector<CriteriaTree const*> const* trees = sCriteriaMgr->GetCriteriaTreesByCriteria(achievementCriteria->ID); + bool allComplete = true; + for (CriteriaTree const* tree : *trees) { - // std. case: increment at 1 - case ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS: - case ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL: - case ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION: - case ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS: /* FIXME: for online player only currently */ - case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED: - case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED: - case ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED: - case ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN: - case ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS: - case ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM: - case ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM: - case ACHIEVEMENT_CRITERIA_TYPE_DEATH: - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST: - case ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP: - case ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON: - case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE: - case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER: - case ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM: - case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET: - case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2: - case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL: - case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2: - case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA: - case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM: - case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT: - case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT: - case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE: - case ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT: - case ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT: - case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL: - case ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS: - case ACHIEVEMENT_CRITERIA_TYPE_HK_RACE: - case ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE: - case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL: - case ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL: - case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS: - case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA: - case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA: // This also behaves like ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA - case ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN: - case ACHIEVEMENT_CRITERIA_TYPE_PLACE_GARRISON_BUILDING: - case ACHIEVEMENT_CRITERIA_TYPE_OWN_BATTLE_PET_COUNT: - SetCriteriaProgress(achievementCriteria, 1, referencePlayer, PROGRESS_ACCUMULATE); - break; - // std case: increment at miscValue1 - case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS: - case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS: - case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD: - case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING: - case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER: - case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL: - case ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY: - case ACHIEVEMENT_CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS:/* FIXME: for online player only currently */ - case ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED: - case ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED: - case ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS: - case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG: - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND: - case ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE: - case ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE: - SetCriteriaProgress(achievementCriteria, miscValue1, referencePlayer, PROGRESS_ACCUMULATE); - break; - case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE: - case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE: - case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE: - case ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM: - case ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM: - case ACHIEVEMENT_CRITERIA_TYPE_CURRENCY: - SetCriteriaProgress(achievementCriteria, miscValue2, referencePlayer, PROGRESS_ACCUMULATE); - break; - // std case: high value at miscValue1 - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID: - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD: /* FIXME: for online player only currently */ - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT: - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED: - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CAST: - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED: - SetCriteriaProgress(achievementCriteria, miscValue1, referencePlayer, PROGRESS_HIGHEST); - break; - case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL: - SetCriteriaProgress(achievementCriteria, referencePlayer->getLevel(), referencePlayer); - break; - case ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL: - 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->Entry->Asset.SkillID)) - SetCriteriaProgress(achievementCriteria, maxSkillvalue, referencePlayer); - break; - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT: - SetCriteriaProgress(achievementCriteria, referencePlayer->GetRewardedQuestCount(), referencePlayer); - break; - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY: - { - time_t nextDailyResetTime = sWorld->GetNextDailyQuestsResetTime(); - CriteriaProgress *progress = GetCriteriaProgress(achievementCriteria); - - if (!miscValue1) // Login case. - { - // reset if player missed one day. - if (progress && progress->date < (nextDailyResetTime - 2 * DAY)) - SetCriteriaProgress(achievementCriteria, 0, referencePlayer, PROGRESS_SET); - continue; - } - - ProgressType progressType; - if (!progress) - // 1st time. Start count. - progressType = PROGRESS_SET; - else if (progress->date < (nextDailyResetTime - 2 * DAY)) - // last progress is older than 2 days. Player missed 1 day => Restart count. - progressType = PROGRESS_SET; - else if (progress->date < (nextDailyResetTime - DAY)) - // last progress is between 1 and 2 days. => 1st time of the day. - progressType = PROGRESS_ACCUMULATE; - else - // last progress is within the day before the reset => Already counted today. - continue; - - SetCriteriaProgress(achievementCriteria, 1, referencePlayer, progressType); - break; - } - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE: - { - uint32 counter = 0; - - const RewardedQuestSet &rewQuests = referencePlayer->getRewardedQuests(); - 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->Entry->Asset.ZoneID) - ++counter; - } - SetCriteriaProgress(achievementCriteria, counter, referencePlayer); - break; - } - case ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING: - // miscValue1 is the ingame fallheight*100 as stored in dbc - SetCriteriaProgress(achievementCriteria, miscValue1, referencePlayer); - break; - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST: - case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL: - case ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA: - case ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP: - case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM: - case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM: - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT: - case ACHIEVEMENT_CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER: - case ACHIEVEMENT_CRITERIA_TYPE_OWN_BATTLE_PET: - SetCriteriaProgress(achievementCriteria, 1, referencePlayer); - break; - case ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT: - SetCriteriaProgress(achievementCriteria, referencePlayer->GetBankBagSlotCount(), referencePlayer); - break; - case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION: - { - int32 reputation = referencePlayer->GetReputationMgr().GetReputation(achievementCriteria->Entry->Asset.FactionID); - if (reputation > 0) - SetCriteriaProgress(achievementCriteria, reputation, referencePlayer); - break; - } - case ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION: - SetCriteriaProgress(achievementCriteria, referencePlayer->GetReputationMgr().GetExaltedFactionCount(), referencePlayer); - break; - case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS: - case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE: - { - uint32 spellCount = 0; - for (PlayerSpellMap::const_iterator spellIter = referencePlayer->GetSpellMap().begin(); - spellIter != referencePlayer->GetSpellMap().end(); - ++spellIter) - { - SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellIter->first); - for (SkillLineAbilityMap::const_iterator skillIter = bounds.first; skillIter != bounds.second; ++skillIter) - { - if (skillIter->second->SkillLine == achievementCriteria->Entry->Asset.SkillID) - spellCount++; - } - } - SetCriteriaProgress(achievementCriteria, spellCount, referencePlayer); - break; - } - case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REVERED_REPUTATION: - SetCriteriaProgress(achievementCriteria, referencePlayer->GetReputationMgr().GetReveredFactionCount(), referencePlayer); - break; - case ACHIEVEMENT_CRITERIA_TYPE_GAIN_HONORED_REPUTATION: - SetCriteriaProgress(achievementCriteria, referencePlayer->GetReputationMgr().GetHonoredFactionCount(), referencePlayer); - break; - case ACHIEVEMENT_CRITERIA_TYPE_KNOWN_FACTIONS: - SetCriteriaProgress(achievementCriteria, referencePlayer->GetReputationMgr().GetVisibleFactionCount(), referencePlayer); - break; - case ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL: - SetCriteriaProgress(achievementCriteria, referencePlayer->GetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS), referencePlayer); - break; - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED: - SetCriteriaProgress(achievementCriteria, referencePlayer->GetMoney(), referencePlayer, PROGRESS_HIGHEST); - break; - case ACHIEVEMENT_CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS: - if (!miscValue1) - SetCriteriaProgress(achievementCriteria, _achievementPoints, referencePlayer, PROGRESS_SET); - else - SetCriteriaProgress(achievementCriteria, miscValue1, referencePlayer, PROGRESS_ACCUMULATE); - break; - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_PERSONAL_RATING: + // don't update already completed criteria if not forced or achievement already complete + if (!(IsCompletedCriteriaTree(tree) && !evenIfCriteriaComplete) || !HasAchieved(tree->Achievement->ID)) { - uint32 reqTeamType = achievementCriteria->Entry->Asset.TeamType; - - if (miscValue1) - { - if (miscValue2 != reqTeamType) - continue; - - SetCriteriaProgress(achievementCriteria, miscValue1, referencePlayer, PROGRESS_HIGHEST); - } - else // login case - { - for (uint32 arena_slot = 0; arena_slot < MAX_ARENA_SLOT; ++arena_slot) - { - uint32 teamId = referencePlayer->GetArenaTeamId(arena_slot); - if (!teamId) - continue; - - ArenaTeam* team = sArenaTeamMgr->GetArenaTeamById(teamId); - if (!team || team->GetType() != reqTeamType) - continue; - - if (ArenaTeamMember const* member = team->GetMember(referencePlayer->GetGUID())) - { - SetCriteriaProgress(achievementCriteria, member->PersonalRating, referencePlayer, PROGRESS_HIGHEST); - break; - } - } - } + allComplete = false; break; } - case ACHIEVEMENT_CRITERIA_TYPE_REACH_GUILD_LEVEL: - SetCriteriaProgress(achievementCriteria, miscValue1, referencePlayer); - break; - // FIXME: not triggered in code as result, need to implement - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID: - case ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA: - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING: - case ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK: - case ACHIEVEMENT_CRITERIA_TYPE_SPENT_GOLD_GUILD_REPAIRS: - case ACHIEVEMENT_CRITERIA_TYPE_CRAFT_ITEMS_GUILD: - case ACHIEVEMENT_CRITERIA_TYPE_CATCH_FROM_POOL: - case ACHIEVEMENT_CRITERIA_TYPE_BUY_GUILD_BANK_SLOTS: - case ACHIEVEMENT_CRITERIA_TYPE_EARN_GUILD_ACHIEVEMENT_POINTS: - case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_BATTLEGROUND: - case ACHIEVEMENT_CRITERIA_TYPE_REACH_BG_RATING: - case ACHIEVEMENT_CRITERIA_TYPE_BUY_GUILD_TABARD: - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_GUILD: - case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILLS_GUILD: - case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE_GUILD: - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ARCHAEOLOGY_PROJECTS: - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE_TYPE: - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE: - case ACHIEVEMENT_CRITERIA_TYPE_LFR_DUNGEONS_COMPLETED: - case ACHIEVEMENT_CRITERIA_TYPE_LFR_LEAVES: - case ACHIEVEMENT_CRITERIA_TYPE_LFR_VOTE_KICKS_INITIATED_BY_PLAYER: - case ACHIEVEMENT_CRITERIA_TYPE_LFR_VOTE_KICKS_NOT_INIT_BY_PLAYER: - case ACHIEVEMENT_CRITERIA_TYPE_BE_KICKED_FROM_LFR: - case ACHIEVEMENT_CRITERIA_TYPE_COUNT_OF_LFR_QUEUE_BOOSTS_BY_TANK: - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_SCENARIO_COUNT: - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_SCENARIO: - case ACHIEVEMENT_CRITERIA_TYPE_CAPTURE_BATTLE_PET: - case ACHIEVEMENT_CRITERIA_TYPE_WIN_PET_BATTLE: - case ACHIEVEMENT_CRITERIA_TYPE_LEVEL_BATTLE_PET: - case ACHIEVEMENT_CRITERIA_TYPE_CAPTURE_BATTLE_PET_CREDIT: - case ACHIEVEMENT_CRITERIA_TYPE_LEVEL_BATTLE_PET_CREDIT: - case ACHIEVEMENT_CRITERIA_TYPE_ENTER_AREA: - case ACHIEVEMENT_CRITERIA_TYPE_LEAVE_AREA: - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DUNGEON_ENCOUNTER: - case ACHIEVEMENT_CRITERIA_TYPE_UPGRADE_GARRISON_BUILDING: - case ACHIEVEMENT_CRITERIA_TYPE_CONSTRUCT_GARRISON_BUILDING: - case ACHIEVEMENT_CRITERIA_TYPE_UPGRADE_GARRISON: - case ACHIEVEMENT_CRITERIA_TYPE_START_GARRISON_MISSION: - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_MISSION_COUNT: - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_MISSION: - case ACHIEVEMENT_CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER_COUNT: - case ACHIEVEMENT_CRITERIA_TYPE_LEARN_GARRISON_BLUEPRINT_COUNT: - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_SHIPMENT: - case ACHIEVEMENT_CRITERIA_TYPE_RAISE_GARRISON_FOLLOWER_ITEM_LEVEL: - case ACHIEVEMENT_CRITERIA_TYPE_RAISE_GARRISON_FOLLOWER_LEVEL: - case ACHIEVEMENT_CRITERIA_TYPE_OWN_TOY: - case ACHIEVEMENT_CRITERIA_TYPE_OWN_TOY_COUNT: - case ACHIEVEMENT_CRITERIA_TYPE_OWN_HEIRLOOMS: - break; // Not implemented yet :( - } - - 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); } - } -} - -// Only player personal achievements require instance id to check realm firsts -// Guild restrictions are handled with additionalConditionType/additionalConditionValue -template<class T> -static uint32 GetInstanceId(T* /*object*/) { return 0xFFFFFFFF; } - -template<> -uint32 GetInstanceId(Player* player) { return player->GetInstanceId(); } - -template<class T> -bool AchievementMgr<T>::IsCompletedCriteriaTree(AchievementCriteriaTree const* tree) -{ - AchievementEntry const* achievement = tree->Achievement; - if (!achievement) - return false; - - // counter can never complete - if (achievement->Flags & ACHIEVEMENT_FLAG_COUNTER) - return false; - - if (achievement->Flags & (ACHIEVEMENT_FLAG_REALM_FIRST_REACH | ACHIEVEMENT_FLAG_REALM_FIRST_KILL)) - { - // someone on this realm has already completed that achievement - if (sAchievementMgr->IsRealmCompleted(achievement, GetInstanceId(GetOwner()))) - 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->Entry->Type)) - { - case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG: - case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE: - case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL: - case ACHIEVEMENT_CRITERIA_TYPE_REACH_GUILD_LEVEL: - case ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL: - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT: - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY: - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE: - case ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE: - case ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE: - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST: - case ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING: - case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET: - case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2: - case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL: - case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2: - case ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE: - case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA: - case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL: - case ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL: - case ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM: - case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA: - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_PERSONAL_RATING: - case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM: - case ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM: - case ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT: - case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION: - case ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION: - case ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP: - case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM: - case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT: - case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT: - case ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS: - case ACHIEVEMENT_CRITERIA_TYPE_HK_RACE: - case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE: - case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM: - case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD: - case ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY: - case ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT: - case ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL: - case ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT: - case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS: - case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL: - case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE: - case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE: - case ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS: - case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS: - case ACHIEVEMENT_CRITERIA_TYPE_CURRENCY: - case ACHIEVEMENT_CRITERIA_TYPE_PLACE_GARRISON_BUILDING: - case ACHIEVEMENT_CRITERIA_TYPE_OWN_BATTLE_PET_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: - case ACHIEVEMENT_CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER: - case ACHIEVEMENT_CRITERIA_TYPE_OWN_BATTLE_PET: - 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 requiredAmount && progress->counter >= requiredAmount; - case ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN: - return true; - // handle all statistic-only criteria here - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND: - case ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP: - case ACHIEVEMENT_CRITERIA_TYPE_DEATH: - case ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON: - case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE: - case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER: - case ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM: - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING: - case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS: - case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS: - case ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS: - case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER: - case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL: - case ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL: - case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE: - case ACHIEVEMENT_CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS: - case ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION: - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID: - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD: - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED: - case ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS: - case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REVERED_REPUTATION: - case ACHIEVEMENT_CRITERIA_TYPE_GAIN_HONORED_REPUTATION: - case ACHIEVEMENT_CRITERIA_TYPE_KNOWN_FACTIONS: - case ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM: - case ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM: - case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED: - case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED: - case ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED: - case ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN: - case ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS: - default: - break; - } - - return false; -} - -template<class T> -void AchievementMgr<T>::CompletedCriteriaFor(AchievementEntry const* achievement, Player* referencePlayer) -{ - // counter can never complete - if (achievement->Flags & ACHIEVEMENT_FLAG_COUNTER) - return; - - // already completed and stored - if (HasAchieved(achievement->ID)) - return; - - if (IsCompletedAchievement(achievement)) - CompletedAchievement(achievement, referencePlayer); -} - -template<class T> -bool AchievementMgr<T>::IsCompletedAchievement(AchievementEntry const* entry) -{ - // counter can never complete - if (entry->Flags & ACHIEVEMENT_FLAG_COUNTER) - return false; - - AchievementCriteriaTree const* tree = sAchievementMgr->GetAchievementCriteriaTree(entry->CriteriaTree); - if (!tree) - return false; + if (allComplete) + continue; - // 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) - { - uint64 progress = 0; - sAchievementMgr->WalkCriteriaTree(tree, [this, &progress](AchievementCriteriaTree const* criteriaTree) - { - if (criteriaTree->Criteria) - if (CriteriaProgress const* criteriaProgress = this->GetCriteriaProgress(criteriaTree->Criteria)) - progress += criteriaProgress->counter; - }); - return progress >= tree->Entry->Amount; + RemoveCriteriaProgress(achievementCriteria); } - - return IsCompletedCriteriaTree(tree); } -template<class T> -CriteriaProgress* AchievementMgr<T>::GetCriteriaProgress(AchievementCriteria const* entry) +void PlayerAchievementMgr::SendAllData(Player const* /*receiver*/) const { - CriteriaProgressMap::iterator iter = m_criteriaProgress.find(entry->ID); - - if (iter == m_criteriaProgress.end()) - return NULL; - - return &(iter->second); -} - -template<class T> -void AchievementMgr<T>::SetCriteriaProgress(AchievementCriteria const* criteria, uint64 changeValue, Player* referencePlayer, ProgressType ptype) -{ - // Don't allow to cheat - doing timed achievements without timer active - 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)", - criteria->ID, changeValue, GetOwner()->GetGUID().ToString().c_str()); + VisibleAchievementCheck filterInvisible; + WorldPackets::Achievement::AllAchievementData achievementData; + achievementData.Data.Earned.reserve(_completedAchievements.size()); + achievementData.Data.Progress.reserve(_criteriaProgress.size()); - CriteriaProgress* progress = GetCriteriaProgress(criteria); - if (!progress) + for (auto itr = _completedAchievements.begin(); itr != _completedAchievements.end(); ++itr) { - // 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 && !criteria->Entry->StartTimer) - return; + AchievementEntry const* achievement = filterInvisible(*itr); + if (!achievement) + continue; - progress = &m_criteriaProgress[criteria->ID]; - progress->counter = changeValue; - } - else - { - uint64 newValue = 0; - switch (ptype) + WorldPackets::Achievement::EarnedAchievement earned; + earned.Id = itr->first; + earned.Date = itr->second.Date; + if (!(achievement->Flags & ACHIEVEMENT_FLAG_ACCOUNT)) { - case PROGRESS_SET: - newValue = changeValue; - break; - case PROGRESS_ACCUMULATE: - { - // avoid overflow - uint64 max_value = std::numeric_limits<uint64>::max(); - newValue = max_value - progress->counter > changeValue ? progress->counter + changeValue : max_value; - break; - } - case PROGRESS_HIGHEST: - newValue = progress->counter < changeValue ? changeValue : progress->counter; - break; + earned.Owner = _owner->GetGUID(); + earned.VirtualRealmAddress = earned.NativeRealmAddress = GetVirtualRealmAddress(); } - - // not update (not mark as changed) if counter will have same value - if (progress->counter == newValue && !criteria->Entry->StartTimer) - return; - - progress->counter = newValue; + achievementData.Data.Earned.push_back(earned); } - progress->changed = true; - progress->date = time(NULL); // set the date to the latest update. - progress->PlayerGUID = referencePlayer->GetGUID(); - - uint32 timeElapsed = 0; - - if (criteria->Entry->StartTimer) + for (auto itr = _criteriaProgress.begin(); itr != _criteriaProgress.end(); ++itr) { - ASSERT(trees); - - 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); - - // Remove the timer, we wont need it anymore - if (IsCompletedCriteriaTree(tree)) - m_timedAchievements.erase(timedIter); - } - } + 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.Data.Progress.push_back(progress); } - SendCriteriaUpdate(criteria, progress, timeElapsed, true); -} - -template<class T> -void AchievementMgr<T>::UpdateTimedAchievements(uint32 timeDiff) -{ - if (!m_timedAchievements.empty()) - { - for (TimedAchievementMap::iterator itr = m_timedAchievements.begin(); itr != m_timedAchievements.end();) - { - // Time is up, remove timer and reset progress - if (itr->second <= timeDiff) - { - AchievementCriteriaTree const* criteriaTree = sAchievementMgr->GetAchievementCriteriaTree(itr->first); - if (criteriaTree->Criteria) - RemoveCriteriaProgress(criteriaTree->Criteria); - - m_timedAchievements.erase(itr++); - } - else - { - itr->second -= timeDiff; - ++itr; - } - } - } + SendPacket(achievementData.Write()); } -template<class T> -void AchievementMgr<T>::StartTimedAchievement(AchievementCriteriaTimedTypes /*type*/, uint32 /*entry*/, uint32 /*timeLost = 0*/) +void PlayerAchievementMgr::SendAchievementInfo(Player* receiver, uint32 /*achievementId = 0 */) const { -} + VisibleAchievementCheck filterInvisible; + WorldPackets::Achievement::RespondInspectAchievements inspectedAchievements; + inspectedAchievements.Player = _owner->GetGUID(); + inspectedAchievements.Data.Earned.reserve(_completedAchievements.size()); + inspectedAchievements.Data.Progress.reserve(_criteriaProgress.size()); -template<> -void AchievementMgr<Player>::StartTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry, uint32 timeLost /* = 0 */) -{ - AchievementCriteriaList const& achievementCriteriaList = sAchievementMgr->GetTimedAchievementCriteriaByType(type); - for (AchievementCriteria const* criteria : achievementCriteriaList) + for (auto itr = _completedAchievements.begin(); itr != _completedAchievements.end(); ++itr) { - if (criteria->Entry->StartAsset != entry) + AchievementEntry const* achievement = filterInvisible(*itr); + if (!achievement) continue; - AchievementCriteriaTreeList const* trees = sAchievementMgr->GetAchievementCriteriaTreesByCriteria(criteria->ID); - bool canStart = false; - for (AchievementCriteriaTree const* tree : *trees) + WorldPackets::Achievement::EarnedAchievement earned; + earned.Id = itr->first; + earned.Date = itr->second.Date; + if (!(achievement->Flags & ACHIEVEMENT_FLAG_ACCOUNT)) { - if (m_timedAchievements.find(tree->ID) == m_timedAchievements.end() && !IsCompletedCriteriaTree(tree)) - { - // Start the timer - if (criteria->Entry->StartTimer * IN_MILLISECONDS > timeLost) - { - m_timedAchievements[tree->ID] = criteria->Entry->StartTimer * IN_MILLISECONDS - timeLost; - canStart = true; - } - } + earned.Owner = _owner->GetGUID(); + earned.VirtualRealmAddress = earned.NativeRealmAddress = GetVirtualRealmAddress(); } - - if (!canStart) - continue; - - // and at client too - SetCriteriaProgress(criteria, 0, GetOwner(), PROGRESS_SET); + inspectedAchievements.Data.Earned.push_back(earned); } -} -template<class T> -void AchievementMgr<T>::RemoveTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry) -{ - AchievementCriteriaList const& achievementCriteriaList = sAchievementMgr->GetTimedAchievementCriteriaByType(type); - for (AchievementCriteria const* criteria : achievementCriteriaList) + for (auto itr = _criteriaProgress.begin(); itr != _criteriaProgress.end(); ++itr) { - if (criteria->Entry->StartAsset != entry) - 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(criteria); + 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; + inspectedAchievements.Data.Progress.push_back(progress); } + + receiver->GetSession()->SendPacket(inspectedAchievements.Write()); } -template<> -void AchievementMgr<Player>::CompletedAchievement(AchievementEntry const* achievement, Player* referencePlayer) +void PlayerAchievementMgr::CompletedAchievement(AchievementEntry const* achievement, Player* referencePlayer) { // disable for gamemasters with GM-mode enabled - if (GetOwner()->IsGameMaster()) + if (_owner->IsGameMaster()) return; if (achievement->Flags & ACHIEVEMENT_FLAG_COUNTER || HasAchieved(achievement->ID)) @@ -1739,22 +447,23 @@ void AchievementMgr<Player>::CompletedAchievement(AchievementEntry const* achiev if (Guild* guild = referencePlayer->GetGuild()) guild->AddGuildNews(GUILD_NEWS_PLAYER_ACHIEVEMENT, referencePlayer->GetGUID(), achievement->Flags & ACHIEVEMENT_FLAG_SHOW_IN_GUILD_HEADER, achievement->ID); - if (!GetOwner()->GetSession()->PlayerLoading()) + if (!_owner->GetSession()->PlayerLoading()) SendAchievementEarned(achievement); - TC_LOG_DEBUG("achievement", "AchievementMgr::CompletedAchievement(%u). %s %s", - achievement->ID, GetOwner()->GetGUID().ToString().c_str(), GetOwner()->GetName().c_str()); + TC_LOG_DEBUG("criteria.achievement", "PlayerAchievementMgr::CompletedAchievement(%u). %s", achievement->ID, GetOwnerInfo().c_str()); - CompletedAchievementData& ca = m_completedAchievements[achievement->ID]; - ca.date = time(NULL); - ca.changed = true; + CompletedAchievementData& ca = _completedAchievements[achievement->ID]; + ca.Date = time(NULL); + ca.Changed = true; - sAchievementMgr->SetRealmCompleted(achievement, GetOwner()->GetInstanceId()); + if (achievement->Flags & (ACHIEVEMENT_FLAG_REALM_FIRST_REACH | ACHIEVEMENT_FLAG_REALM_FIRST_KILL)) + sAchievementMgr->SetRealmCompleted(achievement); - _achievementPoints += achievement->Points; + if (!(achievement->Flags & ACHIEVEMENT_FLAG_TRACKING_FLAG)) + _achievementPoints += achievement->Points; - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT, 0, 0, 0, NULL, referencePlayer); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS, achievement->Points, 0, 0, NULL, referencePlayer); + UpdateCriteria(CRITERIA_TYPE_COMPLETE_ACHIEVEMENT, 0, 0, 0, NULL, referencePlayer); + UpdateCriteria(CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS, achievement->Points, 0, 0, NULL, referencePlayer); // reward items and titles if any AchievementReward const* reward = sAchievementMgr->GetAchievementReward(achievement); @@ -1768,28 +477,28 @@ void AchievementMgr<Player>::CompletedAchievement(AchievementEntry const* achiev //! Since no common attributes were found, (not even in titleRewardFlags field) //! we explicitly check by ID. Maybe in the future we could move the achievement_reward //! condition fields to the condition system. - if (uint32 titleId = reward->titleId[achievement->ID == 1793 ? GetOwner()->GetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_GENDER) : (GetOwner()->GetTeam() == ALLIANCE ? 0 : 1)]) + if (uint32 titleId = reward->TitleId[achievement->ID == 1793 ? _owner->GetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_GENDER) : (_owner->GetTeam() == ALLIANCE ? 0 : 1)]) if (CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(titleId)) - GetOwner()->SetTitle(titleEntry); + _owner->SetTitle(titleEntry); // mail - if (reward->sender) + if (reward->SenderCreatureId) { - MailDraft draft(reward->mailTemplate); + MailDraft draft(uint16(reward->MailTemplateId)); - if (!reward->mailTemplate) + if (!reward->MailTemplateId) { // subject and text - std::string subject = reward->subject; - std::string text = reward->text; + std::string subject = reward->Subject; + std::string text = reward->Body; - LocaleConstant localeConstant = GetOwner()->GetSession()->GetSessionDbLocaleIndex(); + LocaleConstant localeConstant = _owner->GetSession()->GetSessionDbLocaleIndex(); if (localeConstant >= LOCALE_enUS) { if (AchievementRewardLocale const* loc = sAchievementMgr->GetAchievementRewardLocale(achievement)) { - ObjectMgr::GetLocaleString(loc->subject, localeConstant, subject); - ObjectMgr::GetLocaleString(loc->text, localeConstant, text); + ObjectMgr::GetLocaleString(loc->Subject, localeConstant, subject); + ObjectMgr::GetLocaleString(loc->Body, localeConstant, text); } } @@ -1798,7 +507,7 @@ void AchievementMgr<Player>::CompletedAchievement(AchievementEntry const* achiev SQLTransaction trans = CharacterDatabase.BeginTransaction(); - Item* item = reward->itemId ? Item::CreateItem(reward->itemId, 1, GetOwner()) : NULL; + Item* item = reward->ItemId ? Item::CreateItem(reward->ItemId, 1, _owner) : NULL; if (item) { // save new item before send @@ -1808,132 +517,247 @@ void AchievementMgr<Player>::CompletedAchievement(AchievementEntry const* achiev draft.AddItem(item); } - draft.SendMailTo(trans, GetOwner(), MailSender(MAIL_CREATURE, uint64(reward->sender))); + draft.SendMailTo(trans, _owner, MailSender(MAIL_CREATURE, uint64(reward->SenderCreatureId))); CharacterDatabase.CommitTransaction(trans); } } -template<> -void AchievementMgr<Guild>::CompletedAchievement(AchievementEntry const* achievement, Player* referencePlayer) +void PlayerAchievementMgr::SendCriteriaUpdate(Criteria const* criteria, CriteriaProgress const* progress, uint32 timeElapsed, bool timedCompleted) const { - TC_LOG_DEBUG("achievement", "AchievementMgr<Guild>::CompletedAchievement(%u)", achievement->ID); + WorldPackets::Achievement::CriteriaUpdate criteriaUpdate; - if (achievement->Flags & ACHIEVEMENT_FLAG_COUNTER || HasAchieved(achievement->ID)) - return; + criteriaUpdate.CriteriaID = criteria->ID; + criteriaUpdate.Quantity = progress->Counter; + criteriaUpdate.PlayerGUID = _owner->GetGUID(); + criteriaUpdate.Flags = 0; + if (criteria->Entry->StartTimer) + criteriaUpdate.Flags = timedCompleted ? 1 : 0; // 1 is for keeping the counter at 0 in client - if (achievement->Flags & ACHIEVEMENT_FLAG_SHOW_IN_GUILD_NEWS) - if (Guild* guild = referencePlayer->GetGuild()) - guild->AddGuildNews(GUILD_NEWS_GUILD_ACHIEVEMENT, ObjectGuid::Empty, achievement->Flags & ACHIEVEMENT_FLAG_SHOW_IN_GUILD_HEADER, achievement->ID); + criteriaUpdate.CurrentTime = progress->Date; + criteriaUpdate.ElapsedTime = timeElapsed; + criteriaUpdate.CreationTime = 0; - SendAchievementEarned(achievement); - CompletedAchievementData& ca = m_completedAchievements[achievement->ID]; - ca.date = time(NULL); - ca.changed = true; + SendPacket(criteriaUpdate.Write()); +} - if (achievement->Flags & ACHIEVEMENT_FLAG_SHOW_GUILD_MEMBERS) +void PlayerAchievementMgr::SendCriteriaProgressRemoved(uint32 criteriaId) +{ + WorldPackets::Achievement::CriteriaDeleted criteriaDeleted; + criteriaDeleted.CriteriaID = criteriaId; + SendPacket(criteriaDeleted.Write()); +} + +void PlayerAchievementMgr::SendAchievementEarned(AchievementEntry const* achievement) const +{ + // Don't send for achievements with ACHIEVEMENT_FLAG_HIDDEN + if (achievement->Flags & ACHIEVEMENT_FLAG_HIDDEN) + return; + + TC_LOG_DEBUG("criteria.achievement", "PlayerAchievementMgr::SendAchievementEarned(%u)", achievement->ID); + + if (!(achievement->Flags & ACHIEVEMENT_FLAG_TRACKING_FLAG)) { - if (referencePlayer->GetGuildId() == GetOwner()->GetId()) - ca.guids.insert(referencePlayer->GetGUID()); + if (Guild* guild = sGuildMgr->GetGuildById(_owner->GetGuildId())) + { + Trinity::BroadcastTextBuilder _builder(_owner, CHAT_MSG_GUILD_ACHIEVEMENT, BROADCAST_TEXT_ACHIEVEMENT_EARNED, _owner, achievement->ID); + Trinity::LocalizedPacketDo<Trinity::BroadcastTextBuilder> _localizer(_builder); + guild->BroadcastWorker(_localizer, _owner); + } - if (Group const* group = referencePlayer->GetGroup()) - for (GroupReference const* ref = group->GetFirstMember(); ref != NULL; ref = ref->next()) - if (Player const* groupMember = ref->GetSource()) - if (groupMember->GetGuildId() == GetOwner()->GetId()) - ca.guids.insert(groupMember->GetGUID()); + if (achievement->Flags & (ACHIEVEMENT_FLAG_REALM_FIRST_KILL | ACHIEVEMENT_FLAG_REALM_FIRST_REACH)) + { + // broadcast realm first reached + WorldPackets::Achievement::ServerFirstAchievement serverFirstAchievement; + serverFirstAchievement.Name = _owner->GetName(); + serverFirstAchievement.PlayerGUID = _owner->GetGUID(); + serverFirstAchievement.AchievementID = achievement->ID; + sWorld->SendGlobalMessage(serverFirstAchievement.Write()); + } + // if player is in world he can tell his friends about new achievement + else if (_owner->IsInWorld()) + { + Trinity::BroadcastTextBuilder _builder(_owner, CHAT_MSG_ACHIEVEMENT, BROADCAST_TEXT_ACHIEVEMENT_EARNED, _owner, achievement->ID); + Trinity::LocalizedPacketDo<Trinity::BroadcastTextBuilder> _localizer(_builder); + Trinity::PlayerDistWorker<Trinity::LocalizedPacketDo<Trinity::BroadcastTextBuilder> > _worker(_owner, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), _localizer); + _owner->VisitNearbyWorldObject(sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), _worker); + } } - sAchievementMgr->SetRealmCompleted(achievement, referencePlayer->GetInstanceId()); + WorldPackets::Achievement::AchievementEarned achievementEarned; + achievementEarned.Sender = _owner->GetGUID(); + achievementEarned.Earner = _owner->GetGUID(); + achievementEarned.EarnerNativeRealm = achievementEarned.EarnerVirtualRealm = GetVirtualRealmAddress(); + achievementEarned.AchievementID = achievement->ID; + achievementEarned.Time = time(NULL); + if (!(achievement->Flags & ACHIEVEMENT_FLAG_TRACKING_FLAG)) + _owner->SendMessageToSetInRange(achievementEarned.Write(), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), true); + else + _owner->SendDirectMessage(achievementEarned.Write()); +} + +void PlayerAchievementMgr::SendPacket(WorldPacket const* data) const +{ + _owner->SendDirectMessage(data); +} - _achievementPoints += achievement->Points; +CriteriaList const& PlayerAchievementMgr::GetCriteriaByType(CriteriaTypes type) const +{ + return sCriteriaMgr->GetPlayerCriteriaByType(type); +} - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT, 0, 0, 0, NULL, referencePlayer); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS, achievement->Points, 0, 0, NULL, referencePlayer); +GuildAchievementMgr::GuildAchievementMgr(Guild* owner) : _owner(owner) +{ } -struct VisibleAchievementCheck +void GuildAchievementMgr::Reset() { - AchievementEntry const* operator()(CompletedAchievementMap::value_type const& val) + AchievementMgr::Reset(); + + ObjectGuid guid = _owner->GetGUID(); + for (auto iter = _completedAchievements.begin(); iter != _completedAchievements.end(); ++iter) { - AchievementEntry const* achievement = sAchievementMgr->GetAchievement(val.first); - if (achievement && !(achievement->Flags & ACHIEVEMENT_FLAG_HIDDEN)) - return achievement; - return nullptr; + WorldPackets::Achievement::GuildAchievementDeleted guildAchievementDeleted; + guildAchievementDeleted.AchievementID = iter->first; + guildAchievementDeleted.GuildGUID = guid; + guildAchievementDeleted.TimeDeleted = time(NULL); + SendPacket(guildAchievementDeleted.Write()); } -}; -template<class T> -void AchievementMgr<T>::SendAllAchievementData(Player* /*receiver*/) const + _achievementPoints = 0; + _completedAchievements.clear(); + DeleteFromDB(guid); +} + +void GuildAchievementMgr::DeleteFromDB(ObjectGuid const& guid) { - VisibleAchievementCheck filterInvisible; - WorldPackets::Achievement::AllAchievementData achievementData; - achievementData.Data.Earned.reserve(m_completedAchievements.size()); - achievementData.Data.Progress.reserve(m_criteriaProgress.size()); + SQLTransaction trans = CharacterDatabase.BeginTransaction(); - for (auto itr = m_completedAchievements.begin(); itr != m_completedAchievements.end(); ++itr) - { - AchievementEntry const* achievement = filterInvisible(*itr); - if (!achievement) - continue; + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GUILD_ACHIEVEMENTS); + stmt->setUInt64(0, guid.GetCounter()); + trans->Append(stmt); - WorldPackets::Achievement::EarnedAchievement earned; - earned.Id = itr->first; - earned.Date = itr->second.date; - if (!(achievement->Flags & ACHIEVEMENT_FLAG_ACCOUNT)) + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GUILD_ACHIEVEMENT_CRITERIA); + stmt->setUInt64(0, guid.GetCounter()); + trans->Append(stmt); + + CharacterDatabase.CommitTransaction(trans); +} + +void GuildAchievementMgr::LoadFromDB(PreparedQueryResult achievementResult, PreparedQueryResult criteriaResult) +{ + if (achievementResult) + { + do { - earned.Owner = GetOwner()->GetGUID(); - earned.VirtualRealmAddress = earned.NativeRealmAddress = GetVirtualRealmAddress(); - } - achievementData.Data.Earned.push_back(earned); + Field* fields = achievementResult->Fetch(); + uint32 achievementid = fields[0].GetUInt32(); + + // must not happen: cleanup at server startup in sAchievementMgr->LoadCompletedAchievements() + AchievementEntry const* achievement = sAchievementStore.LookupEntry(achievementid); + if (!achievement) + continue; + + CompletedAchievementData& ca = _completedAchievements[achievementid]; + ca.Date = time_t(fields[1].GetUInt32()); + Tokenizer guids(fields[2].GetString(), ' '); + for (uint32 i = 0; i < guids.size(); ++i) + ca.CompletingPlayers.insert(ObjectGuid::Create<HighGuid::Player>(uint64(strtoull(guids[i], nullptr, 10)))); + + ca.Changed = false; + + _achievementPoints += achievement->Points; + } while (achievementResult->NextRow()); } - for (auto itr = m_criteriaProgress.begin(); itr != m_criteriaProgress.end(); ++itr) + if (criteriaResult) { - 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.Data.Progress.push_back(progress); - } + time_t now = time(NULL); + do + { + Field* fields = criteriaResult->Fetch(); + uint32 id = fields[0].GetUInt32(); + uint64 counter = fields[1].GetUInt64(); + time_t date = time_t(fields[2].GetUInt32()); + ObjectGuid::LowType guid = fields[3].GetUInt64(); - SendPacket(achievementData.Write()); + Criteria const* criteria = sCriteriaMgr->GetCriteria(id); + if (!criteria) + { + // we will remove not existed criteria for all guilds + TC_LOG_ERROR("criteria.achievement", "Non-existing achievement criteria %u data removed from table `guild_achievement_progress`.", id); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_ACHIEV_PROGRESS_CRITERIA_GUILD); + stmt->setUInt32(0, uint16(id)); + CharacterDatabase.Execute(stmt); + continue; + } + + if (criteria->Entry->StartTimer && time_t(date + criteria->Entry->StartTimer) < now) + continue; + + CriteriaProgress& progress = _criteriaProgress[id]; + progress.Counter = counter; + progress.Date = date; + progress.PlayerGUID = ObjectGuid::Create<HighGuid::Player>(guid); + progress.Changed = false; + } while (criteriaResult->NextRow()); + } } -template<> -void AchievementMgr<Guild>::SendAllAchievementData(Player* receiver) const +void GuildAchievementMgr::SaveToDB(SQLTransaction& trans) { - VisibleAchievementCheck filterInvisible; - WorldPackets::Achievement::AllGuildAchievements allGuildAchievements; - allGuildAchievements.Earned.reserve(m_completedAchievements.size()); - - for (auto itr = m_completedAchievements.begin(); itr != m_completedAchievements.end(); ++itr) + PreparedStatement* stmt; + std::ostringstream guidstr; + for (auto itr = _completedAchievements.begin(); itr != _completedAchievements.end(); ++itr) { - AchievementEntry const* achievement = filterInvisible(*itr); - if (!achievement) + if (!itr->second.Changed) continue; - WorldPackets::Achievement::EarnedAchievement earned; - earned.Id = itr->first; - earned.Date = itr->second.date; - allGuildAchievements.Earned.push_back(earned); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_ACHIEVEMENT); + stmt->setUInt64(0, _owner->GetId()); + stmt->setUInt32(1, itr->first); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_ACHIEVEMENT); + stmt->setUInt64(0, _owner->GetId()); + stmt->setUInt32(1, itr->first); + stmt->setUInt32(2, uint32(itr->second.Date)); + for (GuidSet::const_iterator gItr = itr->second.CompletingPlayers.begin(); gItr != itr->second.CompletingPlayers.end(); ++gItr) + guidstr << gItr->GetCounter() << ','; + + stmt->setString(3, guidstr.str()); + trans->Append(stmt); + + guidstr.str(""); } - receiver->GetSession()->SendPacket(allGuildAchievements.Write()); + for (auto itr = _criteriaProgress.begin(); itr != _criteriaProgress.end(); ++itr) + { + if (!itr->second.Changed) + continue; + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_ACHIEVEMENT_CRITERIA); + stmt->setUInt64(0, _owner->GetId()); + stmt->setUInt32(1, itr->first); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_ACHIEVEMENT_CRITERIA); + stmt->setUInt64(0, _owner->GetId()); + stmt->setUInt32(1, itr->first); + stmt->setUInt64(2, itr->second.Counter); + stmt->setUInt32(3, uint32(itr->second.Date)); + stmt->setUInt64(4, itr->second.PlayerGUID.GetCounter()); + trans->Append(stmt); + } } -template<> -void AchievementMgr<Player>::SendAchievementInfo(Player* receiver, uint32 /*achievementId = 0 */) const +void GuildAchievementMgr::SendAllData(Player const* receiver) const { VisibleAchievementCheck filterInvisible; - WorldPackets::Achievement::RespondInspectAchievements inspectedAchievements; - inspectedAchievements.Player = GetOwner()->GetGUID(); - inspectedAchievements.Data.Earned.reserve(m_completedAchievements.size()); - inspectedAchievements.Data.Progress.reserve(m_criteriaProgress.size()); + WorldPackets::Achievement::AllGuildAchievements allGuildAchievements; + allGuildAchievements.Earned.reserve(_completedAchievements.size()); - for (auto itr = m_completedAchievements.begin(); itr != m_completedAchievements.end(); ++itr) + for (auto itr = _completedAchievements.begin(); itr != _completedAchievements.end(); ++itr) { AchievementEntry const* achievement = filterInvisible(*itr); if (!achievement) @@ -1941,52 +765,33 @@ void AchievementMgr<Player>::SendAchievementInfo(Player* receiver, uint32 /*achi WorldPackets::Achievement::EarnedAchievement earned; earned.Id = itr->first; - earned.Date = itr->second.date; - if (!(achievement->Flags & ACHIEVEMENT_FLAG_ACCOUNT)) - { - earned.Owner = GetOwner()->GetGUID(); - earned.VirtualRealmAddress = earned.NativeRealmAddress = GetVirtualRealmAddress(); - } - inspectedAchievements.Data.Earned.push_back(earned); - } - - for (auto itr = m_criteriaProgress.begin(); itr != m_criteriaProgress.end(); ++itr) - { - 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; - inspectedAchievements.Data.Progress.push_back(progress); + earned.Date = itr->second.Date; + allGuildAchievements.Earned.push_back(earned); } - receiver->GetSession()->SendPacket(inspectedAchievements.Write()); + receiver->GetSession()->SendPacket(allGuildAchievements.Write()); } -template<> -void AchievementMgr<Guild>::SendAchievementInfo(Player* receiver, uint32 achievementId /*= 0*/) const +void GuildAchievementMgr::SendAchievementInfo(Player* receiver, uint32 achievementId /*= 0*/) const { WorldPackets::Achievement::GuildCriteriaUpdate guildCriteriaUpdate; - if (AchievementEntry const* achievement = sAchievementMgr->GetAchievement(achievementId)) + if (AchievementEntry const* achievement = sAchievementStore.LookupEntry(achievementId)) { - if (AchievementCriteriaTree const* tree = sAchievementMgr->GetAchievementCriteriaTree(achievement->CriteriaTree)) + if (CriteriaTree const* tree = sCriteriaMgr->GetCriteriaTree(achievement->CriteriaTree)) { - sAchievementMgr->WalkCriteriaTree(tree, [this, &guildCriteriaUpdate](AchievementCriteriaTree const* node) + CriteriaMgr::WalkCriteriaTree(tree, [this, &guildCriteriaUpdate](CriteriaTree const* node) { if (node->Criteria) { - auto progress = this->m_criteriaProgress.find(node->Criteria->ID); - if (progress != this->m_criteriaProgress.end()) + auto progress = this->_criteriaProgress.find(node->Criteria->ID); + if (progress != this->_criteriaProgress.end()) { WorldPackets::Achievement::GuildCriteriaProgress guildCriteriaProgress; guildCriteriaProgress.CriteriaID = node->Criteria->ID; guildCriteriaProgress.DateCreated = 0; guildCriteriaProgress.DateStarted = 0; - guildCriteriaProgress.DateUpdated = progress->second.date; - guildCriteriaProgress.Quantity = progress->second.counter; + guildCriteriaProgress.DateUpdated = progress->second.Date; + guildCriteriaProgress.Quantity = progress->second.Counter; guildCriteriaProgress.PlayerGUID = progress->second.PlayerGUID; guildCriteriaProgress.Flags = 0; @@ -2000,1073 +805,186 @@ void AchievementMgr<Guild>::SendAchievementInfo(Player* receiver, uint32 achieve receiver->GetSession()->SendPacket(guildCriteriaUpdate.Write()); } -template<class T> -bool AchievementMgr<T>::HasAchieved(uint32 achievementId) const -{ - return m_completedAchievements.find(achievementId) != m_completedAchievements.end(); -} - -template<class T> -bool AchievementMgr<T>::CanUpdateCriteria(AchievementCriteria const* criteria, AchievementCriteriaTreeList const* trees, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit const* unit, Player* referencePlayer) +void GuildAchievementMgr::SendAllTrackedCriterias(Player* receiver, std::set<uint32> const& trackedCriterias) const { - if (DisableMgr::IsDisabledFor(DISABLE_TYPE_ACHIEVEMENT_CRITERIA, criteria->ID, NULL)) - { - TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: %u Type %s) Disabled", - criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->Entry->Type)); - return false; - } + WorldPackets::Achievement::GuildCriteriaUpdate guildCriteriaUpdate; + guildCriteriaUpdate.Progress.reserve(trackedCriterias.size()); - bool treeRequirementPassed = false; - for (AchievementCriteriaTree const* tree : *trees) + for (uint32 criteriaId : trackedCriterias) { - 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); + auto progress = _criteriaProgress.find(criteriaId); + if (progress == _criteriaProgress.end()) continue; - } - - 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 (!treeRequirementPassed) - return false; - if (!RequirementsSatisfied(criteria, miscValue1, miscValue2, miscValue3, unit, referencePlayer)) - { - TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: %u Type %s) Requirements not satisfied", - criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->Entry->Type)); - return false; - } - - if (criteria->Modifier && !AdditionalRequirementsSatisfied(criteria->Modifier, miscValue1, miscValue2, unit, referencePlayer)) - { - TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: %u Type %s) Requirements have not been satisfied", - criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->Entry->Type)); - return false; - } + WorldPackets::Achievement::GuildCriteriaProgress guildCriteriaProgress; + guildCriteriaProgress.CriteriaID = criteriaId; + guildCriteriaProgress.DateCreated = 0; + guildCriteriaProgress.DateStarted = 0; + guildCriteriaProgress.DateUpdated = progress->second.Date; + guildCriteriaProgress.Quantity = progress->second.Counter; + guildCriteriaProgress.PlayerGUID = progress->second.PlayerGUID; + guildCriteriaProgress.Flags = 0; - if (!ConditionsSatisfied(criteria, referencePlayer)) - { - TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: %u Type %s) Conditions have not been satisfied", - criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->Entry->Type)); - return false; + guildCriteriaUpdate.Progress.push_back(guildCriteriaProgress); } - return true; + receiver->GetSession()->SendPacket(guildCriteriaUpdate.Write()); } -template<class T> -bool AchievementMgr<T>::ConditionsSatisfied(AchievementCriteria const* criteria, Player* referencePlayer) const +void GuildAchievementMgr::CompletedAchievement(AchievementEntry const* achievement, Player* referencePlayer) { - if (!criteria->Entry->FailEvent) - return true; + TC_LOG_DEBUG("criteria.achievement", "GuildAchievementMgr::CompletedAchievement(%u)", achievement->ID); - 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; -} + if (achievement->Flags & ACHIEVEMENT_FLAG_COUNTER || HasAchieved(achievement->ID)) + return; -template<class T> -bool AchievementMgr<T>::RequirementsSatisfied(AchievementCriteria const* achievementCriteria, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit const* unit, Player* referencePlayer) const -{ - switch (AchievementCriteriaTypes(achievementCriteria->Entry->Type)) - { - case ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS: - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST: - case ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION: - case ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING: - case ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN: - case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS: - case ACHIEVEMENT_CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS: - case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER: - case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL: - case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS: - case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING: - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID: - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD: - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED: - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CAST: - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT: - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED: - case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL: - case ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY: - case ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL: - case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD: - case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS: - case ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS: - case ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED: - case ACHIEVEMENT_CRITERIA_TYPE_REACH_GUILD_LEVEL: - case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED: - case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED: - case ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL: - case ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED: - case ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED: - case ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS: - case ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP: - case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL: - case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA: - case ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS: - if (!miscValue1) - return false; - break; - case ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT: - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY: - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT: - case ACHIEVEMENT_CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS: - case ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION: - case ACHIEVEMENT_CRITERIA_TYPE_GAIN_HONORED_REPUTATION: - case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REVERED_REPUTATION: - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED: - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_PERSONAL_RATING: - case ACHIEVEMENT_CRITERIA_TYPE_KNOWN_FACTIONS: - case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL: - case ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN: - break; - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT: - if (m_completedAchievements.find(achievementCriteria->Entry->Asset.AchievementID) == m_completedAchievements.end()) - return false; - break; - case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG: - if (!miscValue1 || achievementCriteria->Entry->Asset.MapID != referencePlayer->GetMapId()) - return false; - break; - case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE: - if (!miscValue1 || achievementCriteria->Entry->Asset.CreatureID != miscValue1) - return false; - break; - case ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL: - case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL: - // update at loading or specific skill update - if (miscValue1 && miscValue1 != achievementCriteria->Entry->Asset.SkillID) - return false; - break; - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE: - if (miscValue1 && miscValue1 != achievementCriteria->Entry->Asset.ZoneID) - return false; - break; - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND: - case ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP: - if (!miscValue1 || referencePlayer->GetMapId() != achievementCriteria->Entry->Asset.MapID) - return false; - break; - case ACHIEVEMENT_CRITERIA_TYPE_DEATH: - { - if (!miscValue1) - return false; - break; - } - case ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON: - { - if (!miscValue1) - return false; + if (achievement->Flags & ACHIEVEMENT_FLAG_SHOW_IN_GUILD_NEWS) + if (Guild* guild = referencePlayer->GetGuild()) + guild->AddGuildNews(GUILD_NEWS_GUILD_ACHIEVEMENT, ObjectGuid::Empty, achievement->Flags & ACHIEVEMENT_FLAG_SHOW_IN_GUILD_HEADER, achievement->ID); - Map const* map = referencePlayer->IsInWorld() ? referencePlayer->GetMap() : sMapMgr->FindMap(referencePlayer->GetMapId(), referencePlayer->GetInstanceId()); - if (!map || !map->IsDungeon()) - return false; + SendAchievementEarned(achievement); + CompletedAchievementData& ca = _completedAchievements[achievement->ID]; + ca.Date = time(NULL); + ca.Changed = true; - //FIXME: work only for instances where max == min for players - if (map->ToInstanceMap()->GetMaxPlayers() != achievementCriteria->Entry->Asset.GroupSize) - return false; - break; - } - case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE: - if (!miscValue1 || miscValue1 != achievementCriteria->Entry->Asset.CreatureID) - return false; - break; - case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER: - if (!miscValue1 || !unit || unit->GetTypeId() != TYPEID_PLAYER) - return false; - break; - case ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM: - if (!miscValue1 || miscValue2 != achievementCriteria->Entry->Asset.DamageType) - return false; - break; - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST: - { - // if miscValues != 0, it contains the questID. - if (miscValue1) - { - if (miscValue1 != achievementCriteria->Entry->Asset.QuestID) - return false; - } - else - { - // login case. - if (!referencePlayer->GetQuestRewardStatus(achievementCriteria->Entry->Asset.QuestID)) - return false; - } + if (achievement->Flags & ACHIEVEMENT_FLAG_SHOW_GUILD_MEMBERS) + { + if (referencePlayer->GetGuildId() == _owner->GetId()) + ca.CompletingPlayers.insert(referencePlayer->GetGUID()); - if (AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria)) - if (!data->Meets(referencePlayer, unit)) - return false; - break; - } - case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET: - case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2: - case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL: - case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2: - if (!miscValue1 || miscValue1 != achievementCriteria->Entry->Asset.SpellID) - return false; - break; - case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL: - if (miscValue1 && miscValue1 != achievementCriteria->Entry->Asset.SpellID) - return false; - - 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->Entry->Asset.LootType) - return false; - break; - case ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM: - if (miscValue1 && achievementCriteria->Entry->Asset.ItemID != miscValue1) - return false; - break; - case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM: - case ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM: - 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->Entry->Asset.WorldMapOverlayID); - if (!worldOverlayEntry) - break; + if (Group const* group = referencePlayer->GetGroup()) + for (GroupReference const* ref = group->GetFirstMember(); ref != NULL; ref = ref->next()) + if (Player const* groupMember = ref->GetSource()) + if (groupMember->GetGuildId() == _owner->GetId()) + ca.CompletingPlayers.insert(groupMember->GetGUID()); + } - bool matchFound = false; - for (int j = 0; j < MAX_WORLD_MAP_OVERLAY_AREA_IDX; ++j) - { - AreaTableEntry const* area = sAreaTableStore.LookupEntry(worldOverlayEntry->AreaID[j]); - if (!area) - break; + if (achievement->Flags & (ACHIEVEMENT_FLAG_REALM_FIRST_REACH | ACHIEVEMENT_FLAG_REALM_FIRST_KILL)) + sAchievementMgr->SetRealmCompleted(achievement); - if (area->AreaBit < 0) - continue; + if (!(achievement->Flags & ACHIEVEMENT_FLAG_TRACKING_FLAG)) + _achievementPoints += achievement->Points; - uint32 playerIndexOffset = uint32(area->AreaBit) / 32; - if (playerIndexOffset >= PLAYER_EXPLORED_ZONES_SIZE) - continue; + UpdateCriteria(CRITERIA_TYPE_COMPLETE_ACHIEVEMENT, 0, 0, 0, NULL, referencePlayer); + UpdateCriteria(CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS, achievement->Points, 0, 0, NULL, referencePlayer); +} - uint32 mask = 1 << (uint32(area->AreaBit) % 32); - if (referencePlayer->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + playerIndexOffset) & mask) - { - matchFound = true; - break; - } - } +void GuildAchievementMgr::SendCriteriaUpdate(Criteria const* entry, CriteriaProgress const* progress, uint32 /*timeElapsed*/, bool /*timedCompleted*/) const +{ + WorldPackets::Achievement::GuildCriteriaUpdate guildCriteriaUpdate; + guildCriteriaUpdate.Progress.resize(1); - if (!matchFound) - return false; - break; - } - case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION: - 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->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->Entry->Asset.RollValue) - return false; - - ItemTemplate const* proto = sObjectMgr->GetItemTemplate(uint32(miscValue1)); - if (!proto) - return false; - break; - } - case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE: - if (!miscValue1 || miscValue1 != achievementCriteria->Entry->Asset.EmoteID) - return false; - break; - case ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE: - case ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE: - if (!miscValue1) - return false; - - if (achievementCriteria->Entry->FailEvent == ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP) - { - if (!referencePlayer->InBattleground()) - return false; + WorldPackets::Achievement::GuildCriteriaProgress& guildCriteriaProgress = guildCriteriaUpdate.Progress[0]; + guildCriteriaProgress.CriteriaID = entry->ID; + guildCriteriaProgress.DateCreated = 0; + guildCriteriaProgress.DateStarted = 0; + guildCriteriaProgress.DateUpdated = progress->Date; + guildCriteriaProgress.Quantity = progress->Counter; + guildCriteriaProgress.PlayerGUID = progress->PlayerGUID; + guildCriteriaProgress.Flags = 0; - // map specific case (BG in fact) expected player targeted damage/heal - if (!unit || unit->GetTypeId() != TYPEID_PLAYER) - return false; - } - break; - case ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT: - case ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT: - if (!miscValue1 || miscValue1 != achievementCriteria->Entry->Asset.GameObjectID) - return false; - break; - case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS: - case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE: - if (miscValue1 && miscValue1 != achievementCriteria->Entry->Asset.SkillID) - return false; - break; - case ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM: - case ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM: - { - if (!miscValue1) - return false; - ItemTemplate const* proto = sObjectMgr->GetItemTemplate(uint32(miscValue1)); - if (!proto || proto->GetQuality() < ITEM_QUALITY_EPIC) - return false; - break; - } - case ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS: - if (!miscValue1 || miscValue1 != achievementCriteria->Entry->Asset.ClassID) - return false; - break; - case ACHIEVEMENT_CRITERIA_TYPE_HK_RACE: - if (!miscValue1 || miscValue1 != achievementCriteria->Entry->Asset.RaceID) - return false; - break; - case ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE: - if (!miscValue1 || miscValue1 != achievementCriteria->Entry->Asset.ObjectiveId) - return false; - break; - case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA: - if (!miscValue1 || miscValue1 != achievementCriteria->Entry->Asset.AreaID) - return false; - break; - case ACHIEVEMENT_CRITERIA_TYPE_CURRENCY: - if (!miscValue1 || !miscValue2 || int64(miscValue2) < 0 - || miscValue1 != achievementCriteria->Entry->Asset.CurrencyID) - return false; - break; - case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA: - if (miscValue1 != achievementCriteria->Entry->Asset.MapID) - return false; - break; - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING: - return false; - case ACHIEVEMENT_CRITERIA_TYPE_PLACE_GARRISON_BUILDING: - if (miscValue1 != achievementCriteria->Entry->Asset.GarrBuildingID) - return false; - break; - default: - break; - } - return true; + _owner->BroadcastPacketIfTrackingAchievement(guildCriteriaUpdate.Write(), entry->ID); } -template<class T> -bool AchievementMgr<T>::AdditionalRequirementsSatisfied(ModifierTreeNode const* tree, uint64 miscValue1, uint64 miscValue2, Unit const* unit, Player* referencePlayer) const +void GuildAchievementMgr::SendCriteriaProgressRemoved(uint32 criteriaId) { - 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]; + WorldPackets::Achievement::GuildCriteriaDeleted guildCriteriaDeleted; + guildCriteriaDeleted.GuildGUID = _owner->GetGUID(); + guildCriteriaDeleted.CriteriaID = criteriaId; + SendPacket(guildCriteriaDeleted.Write()); +} - switch (AchievementCriteriaAdditionalCondition(reqType)) +void GuildAchievementMgr::SendAchievementEarned(AchievementEntry const* achievement) const +{ + if (achievement->Flags & (ACHIEVEMENT_FLAG_REALM_FIRST_KILL | ACHIEVEMENT_FLAG_REALM_FIRST_REACH)) { - 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()->GetDifficultyID()) != 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; - case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_BATTLE_PET_SPECIES: // 91 - if (miscValue1 != reqValue) - return false; - break; - case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_QUALITY: // 145 - { - if (!referencePlayer) - return false; - Garrison* garrison = referencePlayer->GetGarrison(); - if (!garrison) - return false; - Garrison::Follower const* follower = garrison->GetFollower(miscValue1); - if (!follower || follower->PacketInfo.Quality != reqValue) - return false; - - break; - } - case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_LEVEL: // 146 - { - if (!referencePlayer) - return false; - Garrison* garrison = referencePlayer->GetGarrison(); - if (!garrison) - return false; - Garrison::Follower const* follower = garrison->GetFollower(miscValue1); - if (!follower || follower->PacketInfo.FollowerLevel < reqValue) - return false; - - break; - } - case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_ILVL: // 184 - { - if (!referencePlayer) - return false; - Garrison* garrison = referencePlayer->GetGarrison(); - if (!garrison) - return false; - Garrison::Follower const* follower = garrison->GetFollower(miscValue1); - if (!follower || follower->GetItemLevel() < reqValue) - return false; - break; - } - default: - break; + // broadcast realm first reached + WorldPackets::Achievement::ServerFirstAchievement serverFirstAchievement; + serverFirstAchievement.Name = _owner->GetName(); + serverFirstAchievement.PlayerGUID = _owner->GetGUID(); + serverFirstAchievement.AchievementID = achievement->ID; + serverFirstAchievement.GuildAchievement = true; + sWorld->SendGlobalMessage(serverFirstAchievement.Write()); } - return true; + + WorldPackets::Achievement::GuildAchievementEarned guildAchievementEarned; + guildAchievementEarned.AchievementID = achievement->ID; + guildAchievementEarned.GuildGUID = _owner->GetGUID(); + guildAchievementEarned.TimeEarned = time(NULL); + SendPacket(guildAchievementEarned.Write()); } -template class TC_GAME_API AchievementMgr<Player>; -template class TC_GAME_API AchievementMgr<Guild>; +void GuildAchievementMgr::SendPacket(WorldPacket const* data) const +{ + _owner->BroadcastPacket(data); +} -char const* AchievementGlobalMgr::GetCriteriaTypeString(uint32 type) +CriteriaList const& GuildAchievementMgr::GetCriteriaByType(CriteriaTypes type) const { - return GetCriteriaTypeString(AchievementCriteriaTypes(type)); + return sCriteriaMgr->GetGuildCriteriaByType(type); } -char const* AchievementGlobalMgr::GetCriteriaTypeString(AchievementCriteriaTypes type) +std::string PlayerAchievementMgr::GetOwnerInfo() const { - switch (type) - { - case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE: - return "KILL_CREATURE"; - case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG: - return "TYPE_WIN_BG"; - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ARCHAEOLOGY_PROJECTS: - return "COMPLETE_RESEARCH"; - case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL: - return "REACH_LEVEL"; - case ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL: - return "REACH_SKILL_LEVEL"; - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT: - return "COMPLETE_ACHIEVEMENT"; - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT: - return "COMPLETE_QUEST_COUNT"; - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY: - return "COMPLETE_DAILY_QUEST_DAILY"; - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE: - return "COMPLETE_QUESTS_IN_ZONE"; - case ACHIEVEMENT_CRITERIA_TYPE_CURRENCY: - return "CURRENCY"; - case ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE: - return "DAMAGE_DONE"; - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST: - return "COMPLETE_DAILY_QUEST"; - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND: - return "COMPLETE_BATTLEGROUND"; - case ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP: - return "DEATH_AT_MAP"; - case ACHIEVEMENT_CRITERIA_TYPE_DEATH: - return "DEATH"; - case ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON: - return "DEATH_IN_DUNGEON"; - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID: - return "COMPLETE_RAID"; - case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE: - return "KILLED_BY_CREATURE"; - case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER: - return "KILLED_BY_PLAYER"; - case ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING: - return "FALL_WITHOUT_DYING"; - case ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM: - return "DEATHS_FROM"; - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST: - return "COMPLETE_QUEST"; - case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET: - return "BE_SPELL_TARGET"; - case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL: - return "CAST_SPELL"; - case ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE: - return "BG_OBJECTIVE_CAPTURE"; - case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA: - return "HONORABLE_KILL_AT_AREA"; - case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA: - return "WIN_ARENA"; - case ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA: - return "PLAY_ARENA"; - case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL: - return "LEARN_SPELL"; - case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL: - return "HONORABLE_KILL"; - case ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM: - return "OWN_ITEM"; - case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA: - return "WIN_RATED_ARENA"; - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING: - return "HIGHEST_TEAM_RATING"; - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_PERSONAL_RATING: - return "HIGHEST_PERSONAL_RATING"; - case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL: - return "LEARN_SKILL_LEVEL"; - case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM: - return "USE_ITEM"; - case ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM: - return "LOOT_ITEM"; - case ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA: - return "EXPLORE_AREA"; - case ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK: - return "OWN_RANK"; - case ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT: - return "BUY_BANK_SLOT"; - case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION: - return "GAIN_REPUTATION"; - case ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION: - return "GAIN_EXALTED_REPUTATION"; - case ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP: - return "VISIT_BARBER_SHOP"; - case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM: - return "EQUIP_EPIC_ITEM"; - case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT: - return "ROLL_NEED_ON_LOOT"; - case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT: - return "GREED_ON_LOOT"; - case ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS: - return "HK_CLASS"; - case ACHIEVEMENT_CRITERIA_TYPE_HK_RACE: - return "HK_RACE"; - case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE: - return "DO_EMOTE"; - case ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE: - return "HEALING_DONE"; - case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS: - return "GET_KILLING_BLOWS"; - case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM: - return "EQUIP_ITEM"; - case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS: - return "MONEY_FROM_VENDORS"; - case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS: - return "GOLD_SPENT_FOR_TALENTS"; - case ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS: - return "NUMBER_OF_TALENT_RESETS"; - case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD: - return "MONEY_FROM_QUEST_REWARD"; - case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING: - return "GOLD_SPENT_FOR_TRAVELLING"; - case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER: - return "GOLD_SPENT_AT_BARBER"; - case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL: - return "GOLD_SPENT_FOR_MAIL"; - case ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY: - return "LOOT_MONEY"; - case ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT: - return "USE_GAMEOBJECT"; - case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2: - return "BE_SPELL_TARGET2"; - case ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL: - return "SPECIAL_PVP_KILL"; - case ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT: - return "FISH_IN_GAMEOBJECT"; - case ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN: - return "ON_LOGIN"; - case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS: - return "LEARN_SKILLLINE_SPELLS"; - case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL: - return "WIN_DUEL"; - case ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL: - return "LOSE_DUEL"; - case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE: - return "KILL_CREATURE_TYPE"; - case ACHIEVEMENT_CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS: - return "GOLD_EARNED_BY_AUCTIONS"; - case ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION: - return "CREATE_AUCTION"; - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID: - return "HIGHEST_AUCTION_BID"; - case ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS: - return "WON_AUCTIONS"; - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD: - return "HIGHEST_AUCTION_SOLD"; - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED: - return "HIGHEST_GOLD_VALUE_OWNED"; - case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REVERED_REPUTATION: - return "GAIN_REVERED_REPUTATION"; - case ACHIEVEMENT_CRITERIA_TYPE_GAIN_HONORED_REPUTATION: - return "GAIN_HONORED_REPUTATION"; - case ACHIEVEMENT_CRITERIA_TYPE_KNOWN_FACTIONS: - return "KNOWN_FACTIONS"; - case ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM: - return "LOOT_EPIC_ITEM"; - case ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM: - return "RECEIVE_EPIC_ITEM"; - case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED: - return "ROLL_NEED"; - case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED: - return "ROLL_GREED"; - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT: - return "HIT_DEALT"; - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED: - return "HIT_RECEIVED"; - case ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED: - return "TOTAL_DAMAGE_RECEIVED"; - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CAST: - return "HIGHEST_HEAL_CAST"; - case ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED: - return "TOTAL_HEALING_RECEIVED"; - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED: - return "HIGHEST_HEALING_RECEIVED"; - case ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED: - return "QUEST_ABANDONED"; - case ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN: - return "FLIGHT_PATHS_TAKEN"; - case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE: - return "LOOT_TYPE"; - case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2: - return "CAST_SPELL2"; - case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE: - return "LEARN_SKILL_LINE"; - case ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL: - return "EARN_HONORABLE_KILL"; - case ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS: - return "ACCEPTED_SUMMONINGS"; - case ACHIEVEMENT_CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS: - return "EARN_ACHIEVEMENT_POINTS"; - case ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS: - return "USE_LFD_TO_GROUP_WITH_PLAYERS"; - case ACHIEVEMENT_CRITERIA_TYPE_SPENT_GOLD_GUILD_REPAIRS: - return "SPENT_GOLD_GUILD_REPAIRS"; - case ACHIEVEMENT_CRITERIA_TYPE_REACH_GUILD_LEVEL: - return "REACH_GUILD_LEVEL"; - case ACHIEVEMENT_CRITERIA_TYPE_CRAFT_ITEMS_GUILD: - return "CRAFT_ITEMS_GUILD"; - case ACHIEVEMENT_CRITERIA_TYPE_CATCH_FROM_POOL: - return "CATCH_FROM_POOL"; - case ACHIEVEMENT_CRITERIA_TYPE_BUY_GUILD_BANK_SLOTS: - return "BUY_GUILD_BANK_SLOTS"; - case ACHIEVEMENT_CRITERIA_TYPE_EARN_GUILD_ACHIEVEMENT_POINTS: - return "EARN_GUILD_ACHIEVEMENT_POINTS"; - case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_BATTLEGROUND: - return "WIN_RATED_BATTLEGROUND"; - case ACHIEVEMENT_CRITERIA_TYPE_REACH_BG_RATING: - return "REACH_BG_RATING"; - case ACHIEVEMENT_CRITERIA_TYPE_BUY_GUILD_TABARD: - return "BUY_GUILD_TABARD"; - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_GUILD: - return "COMPLETE_QUESTS_GUILD"; - case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILLS_GUILD: - return "HONORABLE_KILLS_GUILD"; - case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE_GUILD: - return "KILL_CREATURE_TYPE_GUILD"; - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE_TYPE: - return "GUILD_CHALLENGE_TYPE"; - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE: - return "GUILD_CHALLENGE"; - case ACHIEVEMENT_CRITERIA_TYPE_LFR_DUNGEONS_COMPLETED: - return "LFR_DUNGEONS_COMPLETED"; - case ACHIEVEMENT_CRITERIA_TYPE_LFR_LEAVES: - return "LFR_LEAVES"; - case ACHIEVEMENT_CRITERIA_TYPE_LFR_VOTE_KICKS_INITIATED_BY_PLAYER: - return "LFR_VOTE_KICKS_INITIATED_BY_PLAYER"; - case ACHIEVEMENT_CRITERIA_TYPE_LFR_VOTE_KICKS_NOT_INIT_BY_PLAYER: - return "LFR_VOTE_KICKS_NOT_INIT_BY_PLAYER"; - case ACHIEVEMENT_CRITERIA_TYPE_BE_KICKED_FROM_LFR: - return "BE_KICKED_FROM_LFR"; - case ACHIEVEMENT_CRITERIA_TYPE_COUNT_OF_LFR_QUEUE_BOOSTS_BY_TANK: - return "COUNT_OF_LFR_QUEUE_BOOSTS_BY_TANK"; - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_SCENARIO_COUNT: - return "COMPLETE_SCENARIO_COUNT"; - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_SCENARIO: - return "COMPLETE_SCENARIO"; - case ACHIEVEMENT_CRITERIA_TYPE_OWN_BATTLE_PET: - return "OWN_BATTLE_PET"; - case ACHIEVEMENT_CRITERIA_TYPE_OWN_BATTLE_PET_COUNT: - return "OWN_BATTLE_PET_COUNT"; - case ACHIEVEMENT_CRITERIA_TYPE_CAPTURE_BATTLE_PET: - return "CAPTURE_BATTLE_PET"; - case ACHIEVEMENT_CRITERIA_TYPE_WIN_PET_BATTLE: - return "WIN_PET_BATTLE"; - case ACHIEVEMENT_CRITERIA_TYPE_LEVEL_BATTLE_PET: - return "LEVEL_BATTLE_PET"; - case ACHIEVEMENT_CRITERIA_TYPE_CAPTURE_BATTLE_PET_CREDIT: - return "CAPTURE_BATTLE_PET_CREDIT"; - case ACHIEVEMENT_CRITERIA_TYPE_LEVEL_BATTLE_PET_CREDIT: - return "LEVEL_BATTLE_PET_CREDIT"; - case ACHIEVEMENT_CRITERIA_TYPE_ENTER_AREA: - return "ENTER_AREA"; - case ACHIEVEMENT_CRITERIA_TYPE_LEAVE_AREA: - return "LEAVE_AREA"; - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DUNGEON_ENCOUNTER: - return "COMPLETE_DUNGEON_ENCOUNTER"; - case ACHIEVEMENT_CRITERIA_TYPE_PLACE_GARRISON_BUILDING: - return "PLACE_GARRISON_BUILDING"; - case ACHIEVEMENT_CRITERIA_TYPE_UPGRADE_GARRISON_BUILDING: - return "UPGRADE_GARRISON_BUILDING"; - case ACHIEVEMENT_CRITERIA_TYPE_CONSTRUCT_GARRISON_BUILDING: - return "CONSTRUCT_GARRISON_BUILDING"; - case ACHIEVEMENT_CRITERIA_TYPE_UPGRADE_GARRISON: - return "UPGRADE_GARRISON"; - case ACHIEVEMENT_CRITERIA_TYPE_START_GARRISON_MISSION: - return "START_GARRISON_MISSION"; - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_MISSION_COUNT: - return "COMPLETE_GARRISON_MISSION_COUNT"; - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_MISSION: - return "COMPLETE_GARRISON_MISSION"; - case ACHIEVEMENT_CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER_COUNT: - return "RECRUIT_GARRISON_FOLLOWER_COUNT"; - case ACHIEVEMENT_CRITERIA_TYPE_LEARN_GARRISON_BLUEPRINT_COUNT: - return "LEARN_GARRISON_BLUEPRINT_COUNT"; - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_SHIPMENT: - return "COMPLETE_GARRISON_SHIPMENT"; - case ACHIEVEMENT_CRITERIA_TYPE_RAISE_GARRISON_FOLLOWER_ITEM_LEVEL: - return "RAISE_GARRISON_FOLLOWER_ITEM_LEVEL"; - case ACHIEVEMENT_CRITERIA_TYPE_RAISE_GARRISON_FOLLOWER_LEVEL: - return "RAISE_GARRISON_FOLLOWER_LEVEL"; - case ACHIEVEMENT_CRITERIA_TYPE_OWN_TOY: - return "OWN_TOY"; - case ACHIEVEMENT_CRITERIA_TYPE_OWN_TOY_COUNT: - return "OWN_TOY_COUNT"; - case ACHIEVEMENT_CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER: - return "RECRUIT_GARRISON_FOLLOWER"; - case ACHIEVEMENT_CRITERIA_TYPE_OWN_HEIRLOOMS: - return "OWN_HEIRLOOMS"; - } - return "MISSING_TYPE"; + return Trinity::StringFormat("%s %s", _owner->GetGUID().ToString().c_str(), _owner->GetName().c_str()); } -AchievementGlobalMgr* AchievementGlobalMgr::instance() +std::string GuildAchievementMgr::GetOwnerInfo() const +{ + return Trinity::StringFormat("Guild ID " UI64FMTD " %s", _owner->GetId(), _owner->GetName().c_str()); +} + +AchievementGlobalMgr* AchievementGlobalMgr::Instance() { static AchievementGlobalMgr instance; return &instance; } -//========================================================== -AchievementGlobalMgr::~AchievementGlobalMgr() +std::vector<AchievementEntry const*> const* AchievementGlobalMgr::GetAchievementByReferencedId(uint32 id) const { - 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; + auto itr = _achievementListByReferencedId.find(id); + return itr != _achievementListByReferencedId.end() ? &itr->second : NULL; } -void AchievementGlobalMgr::LoadAchievementCriteriaModifiersTree() +AchievementReward const* AchievementGlobalMgr::GetAchievementReward(AchievementEntry const* achievement) const { - uint32 oldMSTime = getMSTime(); - - if (sModifierTreeStore.GetNumRows() == 0) - { - TC_LOG_ERROR("server.loading", ">> Loaded 0 achievement criteria modifiers."); - return; - } + auto iter = _achievementRewards.find(achievement->ID); + return iter != _achievementRewards.end() ? &iter->second : NULL; +} - // Load modifier tree nodes - for (uint32 i = 0; i < sModifierTreeStore.GetNumRows(); ++i) - { - ModifierTreeEntry const* tree = sModifierTreeStore.LookupEntry(i); - if (!tree) - continue; +AchievementRewardLocale const* AchievementGlobalMgr::GetAchievementRewardLocale(AchievementEntry const* achievement) const +{ + auto iter = _achievementRewardLocales.find(achievement->ID); + return iter != _achievementRewardLocales.end() ? &iter->second : NULL; +} - ModifierTreeNode* node = new ModifierTreeNode(); - node->Entry = tree; - _criteriaModifiers[node->Entry->ID] = node; - } +bool AchievementGlobalMgr::IsRealmCompleted(AchievementEntry const* achievement) const +{ + auto itr = _allCompletedAchievements.find(achievement->ID); + if (itr == _allCompletedAchievements.end()) + return false; - // Build tree - for (auto itr = _criteriaModifiers.begin(); itr != _criteriaModifiers.end(); ++itr) - { - if (!itr->second->Entry->Parent) - continue; + if (itr->second == std::chrono::system_clock::time_point::min()) + return false; - auto parent = _criteriaModifiers.find(itr->second->Entry->Parent); - if (parent != _criteriaModifiers.end()) - parent->second->Children.push_back(itr->second); - } + // Allow completing the realm first kill for entire minute after first person did it + // it may allow more than one group to achieve it (highly unlikely) + // but apparently this is how blizz handles it as well + if (achievement->Flags & ACHIEVEMENT_FLAG_REALM_FIRST_KILL) + return (std::chrono::system_clock::now() - itr->second) > Minutes(1); - TC_LOG_INFO("server.loading", ">> Loaded %u achievement criteria modifiers in %u ms", uint32(_criteriaModifiers.size()), GetMSTimeDiffToNow(oldMSTime)); + return true; } -void AchievementGlobalMgr::LoadAchievementCriteriaList() +void AchievementGlobalMgr::SetRealmCompleted(AchievementEntry const* achievement) { - uint32 oldMSTime = getMSTime(); - - if (sCriteriaTreeStore.GetNumRows() == 0) - { - TC_LOG_ERROR("server.loading", ">> Loaded 0 achievement criteria."); + if (IsRealmCompleted(achievement)) 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 (!cur->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; - - _achievementCriteriaTrees[achievementCriteriaTree->Entry->ID] = 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); - while (parent != _achievementCriteriaTrees.end()) - { - auto cur = parent; - parent = _achievementCriteriaTrees.find(parent->second->Entry->Parent); - if (parent == _achievementCriteriaTrees.end()) - { - if (sCriteriaStore.LookupEntry(itr->second->Entry->CriteriaID)) - _achievementCriteriaTreeByCriteria[itr->second->Entry->CriteriaID].push_back(cur->second); - } - } - } - else if (sCriteriaStore.LookupEntry(itr->second->Entry->CriteriaID)) - _achievementCriteriaTreeByCriteria[itr->second->Entry->CriteriaID].push_back(itr->second); - } - - // Load criteria - uint32 criterias = 0; - uint32 guildCriterias = 0; - for (uint32 i = 0; i < sCriteriaStore.GetNumRows(); ++i) - { - CriteriaEntry const* criteria = sCriteriaStore.LookupEntry(i); - if (!criteria) - continue; - - auto treeItr = _achievementCriteriaTreeByCriteria.find(i); - if (treeItr == _achievementCriteriaTreeByCriteria.end()) - continue; - - AchievementCriteria* achievementCriteria = new AchievementCriteria(); - achievementCriteria->ID = i; - achievementCriteria->Entry = criteria; - auto mod = _criteriaModifiers.find(criteria->ModifierTreeId); - if (mod != _criteriaModifiers.end()) - achievementCriteria->Modifier = mod->second; - - _achievementCriteria[achievementCriteria->ID] = achievementCriteria; - - for (AchievementCriteriaTree const* tree : treeItr->second) - { - if (tree->Achievement->Flags & ACHIEVEMENT_FLAG_GUILD) - achievementCriteria->FlagsCu |= ACHIEVEMENT_CRITERIA_FLAG_CU_GUILD; - else if (tree->Achievement->Flags & ACHIEVEMENT_FLAG_ACCOUNT) - achievementCriteria->FlagsCu |= ACHIEVEMENT_CRITERIA_FLAG_CU_ACCOUNT; - else - achievementCriteria->FlagsCu |= ACHIEVEMENT_CRITERIA_FLAG_CU_PLAYER; - } - - if (achievementCriteria->FlagsCu & ACHIEVEMENT_CRITERIA_FLAG_CU_GUILD) - { - ++guildCriterias; - _guildAchievementCriteriasByType[criteria->Type].push_back(achievementCriteria); - } - - if (achievementCriteria->FlagsCu & (ACHIEVEMENT_CRITERIA_FLAG_CU_PLAYER | ACHIEVEMENT_CRITERIA_FLAG_CU_ACCOUNT)) - { - ++criterias; - _achievementCriteriasByType[criteria->Type].push_back(achievementCriteria); - } - if (criteria->StartTimer) - _achievementCriteriasByTimedType[criteria->StartEvent].push_back(achievementCriteria); - } - - for (auto& p : _achievementCriteriaTrees) - const_cast<AchievementCriteriaTree*>(p.second)->Criteria = GetAchievementCriteria(p.second->Entry->CriteriaID); - - TC_LOG_INFO("server.loading", ">> Loaded %u achievement criteria and %u guild achievement crieteria in %u ms.", criterias, guildCriterias, GetMSTimeDiffToNow(oldMSTime)); + _allCompletedAchievements[achievement->ID] = std::chrono::system_clock::now(); } +//========================================================== void AchievementGlobalMgr::LoadAchievementReferenceList() { uint32 oldMSTime = getMSTime(); @@ -3081,7 +999,7 @@ void AchievementGlobalMgr::LoadAchievementReferenceList() for (uint32 entryId = 0; entryId < sAchievementStore.GetNumRows(); ++entryId) { - AchievementEntry const* achievement = sAchievementMgr->GetAchievement(entryId); + AchievementEntry const* achievement = sAchievementStore.LookupEntry(entryId); if (!achievement || !achievement->SharesCriteria) continue; @@ -3090,77 +1008,23 @@ void AchievementGlobalMgr::LoadAchievementReferenceList() } // Once Bitten, Twice Shy (10 player) - Icecrown Citadel - if (AchievementEntry const* achievement = sAchievementMgr->GetAchievement(4539)) + if (AchievementEntry const* achievement = sAchievementStore.LookupEntry(4539)) 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)); } -void AchievementGlobalMgr::LoadAchievementCriteriaData() -{ - uint32 oldMSTime = getMSTime(); - - _criteriaDataMap.clear(); // need for reload case - - QueryResult result = WorldDatabase.Query("SELECT criteria_id, type, value1, value2, ScriptName FROM achievement_criteria_data"); - - if (!result) - { - TC_LOG_INFO("server.loading", ">> Loaded 0 additional achievement criteria data. DB table `achievement_criteria_data` is empty."); - return; - } - - uint32 count = 0; - - do - { - Field* fields = result->Fetch(); - uint32 criteria_id = fields[0].GetUInt32(); - - AchievementCriteria const* criteria = sAchievementMgr->GetAchievementCriteria(criteria_id); - - if (!criteria) - { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` contains data for non-existing criteria (Entry: %u). Ignored.", criteria_id); - continue; - } - - uint32 dataType = fields[1].GetUInt8(); - std::string scriptName = fields[4].GetString(); - uint32 scriptId = 0; - if (!scriptName.empty()) - { - if (dataType != ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT) - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` contains a ScriptName for non-scripted data type (Entry: %u, type %u), useless data.", criteria_id, dataType); - else - scriptId = sObjectMgr->GetScriptId(scriptName); - } - - AchievementCriteriaData data(dataType, fields[2].GetUInt32(), fields[3].GetUInt32(), scriptId); - - if (!data.IsValid(criteria)) - continue; - - // this will allocate empty data set storage - AchievementCriteriaDataSet& dataSet = _criteriaDataMap[criteria_id]; - dataSet.SetCriteriaId(criteria_id); - - // add real data only for not NONE data types - if (data.dataType != ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE) - dataSet.Add(data); - - // counting data by and data types - ++count; - } - while (result->NextRow()); - - TC_LOG_INFO("server.loading", ">> Loaded %u additional achievement criteria data in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); -} - void AchievementGlobalMgr::LoadCompletedAchievements() { uint32 oldMSTime = getMSTime(); + // Populate _allCompletedAchievements with all realm first achievement ids to make multithreaded access safer + // while it will not prevent races, it will prevent crashes that happen because std::unordered_map key was added + // instead the only potential race will happen on value associated with the key + for (AchievementEntry const* achievement : sAchievementStore) + if (achievement->Flags & (ACHIEVEMENT_FLAG_REALM_FIRST_REACH | ACHIEVEMENT_FLAG_REALM_FIRST_KILL)) + _allCompletedAchievements[achievement->ID] = std::chrono::system_clock::time_point::min(); + QueryResult result = CharacterDatabase.Query("SELECT achievement FROM character_achievement GROUP BY achievement"); if (!result) @@ -3173,21 +1037,21 @@ void AchievementGlobalMgr::LoadCompletedAchievements() { Field* fields = result->Fetch(); - uint16 achievementId = fields[0].GetUInt16(); - const AchievementEntry* achievement = sAchievementMgr->GetAchievement(achievementId); + uint32 achievementId = fields[0].GetUInt32(); + AchievementEntry const* achievement = sAchievementStore.LookupEntry(achievementId); if (!achievement) { // Remove non-existing achievements from all characters - TC_LOG_ERROR("achievement", "Non-existing achievement %u data has been removed from the table `character_achievement`.", achievementId); + TC_LOG_ERROR("criteria.achievement", "Non-existing achievement %u data has been removed from the table `character_achievement`.", achievementId); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_ACHIEVMENT); - stmt->setUInt16(0, uint16(achievementId)); + stmt->setUInt32(0, achievementId); CharacterDatabase.Execute(stmt); continue; } else if (achievement->Flags & (ACHIEVEMENT_FLAG_REALM_FIRST_REACH | ACHIEVEMENT_FLAG_REALM_FIRST_KILL)) - _allCompletedAchievements[achievementId] = uint32(0xFFFFFFFF); + _allCompletedAchievements[achievementId] = std::chrono::system_clock::time_point::max(); } while (result->NextRow()); @@ -3215,7 +1079,7 @@ void AchievementGlobalMgr::LoadRewards() { Field* fields = result->Fetch(); uint32 entry = fields[0].GetUInt32(); - AchievementEntry const* achievement = GetAchievement(entry); + AchievementEntry const* achievement = sAchievementStore.LookupEntry(entry); if (!achievement) { TC_LOG_ERROR("sql.sql", "Table `achievement_reward` contains a wrong achievement entry (Entry: %u), ignored.", entry); @@ -3223,85 +1087,85 @@ void AchievementGlobalMgr::LoadRewards() } AchievementReward reward; - reward.titleId[0] = fields[1].GetUInt32(); - reward.titleId[1] = fields[2].GetUInt32(); - reward.itemId = fields[3].GetUInt32(); - reward.sender = fields[4].GetUInt32(); - reward.subject = fields[5].GetString(); - reward.text = fields[6].GetString(); - reward.mailTemplate = fields[7].GetUInt32(); + reward.TitleId[0] = fields[1].GetUInt32(); + reward.TitleId[1] = fields[2].GetUInt32(); + reward.ItemId = fields[3].GetUInt32(); + reward.SenderCreatureId = fields[4].GetUInt32(); + reward.Subject = fields[5].GetString(); + reward.Body = fields[6].GetString(); + reward.MailTemplateId = fields[7].GetUInt32(); // must be title or mail at least - if (!reward.titleId[0] && !reward.titleId[1] && !reward.sender) + if (!reward.TitleId[0] && !reward.TitleId[1] && !reward.SenderCreatureId) { TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) does not contain title or item reward data. Ignored.", entry); continue; } - if (achievement->Faction == ACHIEVEMENT_FACTION_ANY && (!reward.titleId[0] ^ !reward.titleId[1])) - TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) contains the title (A: %u H: %u) for only one team.", entry, reward.titleId[0], reward.titleId[1]); + if (achievement->Faction == ACHIEVEMENT_FACTION_ANY && (!reward.TitleId[0] ^ !reward.TitleId[1])) + TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) contains the title (A: %u H: %u) for only one team.", entry, reward.TitleId[0], reward.TitleId[1]); - if (reward.titleId[0]) + if (reward.TitleId[0]) { - CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(reward.titleId[0]); + CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(reward.TitleId[0]); if (!titleEntry) { - TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) contains an invalid title id (%u) in `title_A`, set to 0", entry, reward.titleId[0]); - reward.titleId[0] = 0; + TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) contains an invalid title id (%u) in `title_A`, set to 0", entry, reward.TitleId[0]); + reward.TitleId[0] = 0; } } - if (reward.titleId[1]) + if (reward.TitleId[1]) { - CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(reward.titleId[1]); + CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(reward.TitleId[1]); if (!titleEntry) { - TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) contains an invalid title id (%u) in `title_H`, set to 0", entry, reward.titleId[1]); - reward.titleId[1] = 0; + TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) contains an invalid title id (%u) in `title_H`, set to 0", entry, reward.TitleId[1]); + reward.TitleId[1] = 0; } } //check mail data before item for report including wrong item case - if (reward.sender) + if (reward.SenderCreatureId) { - if (!sObjectMgr->GetCreatureTemplate(reward.sender)) + if (!sObjectMgr->GetCreatureTemplate(reward.SenderCreatureId)) { - TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) contains an invalid creature entry %u as sender, mail reward skipped.", entry, reward.sender); - reward.sender = 0; + TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) contains an invalid creature entry %u as sender, mail reward skipped.", entry, reward.SenderCreatureId); + reward.SenderCreatureId = 0; } } else { - if (reward.itemId) + if (reward.ItemId) TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) does not have sender data, but contains an item reward. Item will not be rewarded.", entry); - if (!reward.subject.empty()) + if (!reward.Subject.empty()) TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) does not have sender data, but contains a mail subject.", entry); - if (!reward.text.empty()) + if (!reward.Body.empty()) TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) does not have sender data, but contains mail text.", entry); - if (reward.mailTemplate) - TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) does not have sender data, but has a mailTemplate.", entry); + if (reward.MailTemplateId) + TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) does not have sender data, but has a MailTemplateId.", entry); } - if (reward.mailTemplate) + if (reward.MailTemplateId) { - if (!sMailTemplateStore.LookupEntry(reward.mailTemplate)) + if (!sMailTemplateStore.LookupEntry(reward.MailTemplateId)) { - TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) is using an invalid mailTemplate (%u).", entry, reward.mailTemplate); - reward.mailTemplate = 0; + TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) is using an invalid MailTemplateId (%u).", entry, reward.MailTemplateId); + reward.MailTemplateId = 0; } - else if (!reward.subject.empty() || !reward.text.empty()) - TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) is using mailTemplate (%u) and mail subject/text.", entry, reward.mailTemplate); + else if (!reward.Subject.empty() || !reward.Body.empty()) + TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) is using MailTemplateId (%u) and mail subject/text.", entry, reward.MailTemplateId); } - if (reward.itemId) + if (reward.ItemId) { - if (!sObjectMgr->GetItemTemplate(reward.itemId)) + if (!sObjectMgr->GetItemTemplate(reward.ItemId)) { - TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) contains an invalid item id %u, reward mail will not contain the rewarded item.", entry, reward.itemId); - reward.itemId = 0; + TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) contains an invalid item id %u, reward mail will not contain the rewarded item.", entry, reward.ItemId); + reward.ItemId = 0; } } @@ -3346,41 +1210,11 @@ void AchievementGlobalMgr::LoadRewardLocales() for (uint8 i = OLD_TOTAL_LOCALES - 1; i > 0; --i) { LocaleConstant locale = (LocaleConstant) i; - ObjectMgr::AddLocaleString(fields[1 + 2 * (i - 1)].GetString(), locale, data.subject); - ObjectMgr::AddLocaleString(fields[1 + 2 * (i - 1) + 1].GetString(), locale, data.text); + ObjectMgr::AddLocaleString(fields[1 + 2 * (i - 1)].GetString(), locale, data.Subject); + ObjectMgr::AddLocaleString(fields[1 + 2 * (i - 1) + 1].GetString(), locale, data.Body); } } while (result->NextRow()); 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 -{ - return sAchievementStore.LookupEntry(achievementId); -} - -AchievementCriteriaTree const* AchievementGlobalMgr::GetAchievementCriteriaTree(uint32 criteriaTreeId) const -{ - 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 : _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 16f4d20614a..f009b202af4 100644 --- a/src/server/game/Achievements/AchievementMgr.h +++ b/src/server/game/Achievements/AchievementMgr.h @@ -19,485 +19,158 @@ #ifndef __TRINITY_ACHIEVEMENTMGR_H #define __TRINITY_ACHIEVEMENTMGR_H -#include <map> -#include <string> +#include "CriteriaHandler.h" -#include "Common.h" -#include "DatabaseEnv.h" -#include "DBCEnums.h" -#include "DBCStores.h" -#include "ObjectGuid.h" - -class Unit; -class Player; class Guild; -class WorldPacket; -struct ModifierTreeNode +struct AchievementReward { - ModifierTreeEntry const* Entry; - std::vector<ModifierTreeNode const*> Children; + uint32 TitleId[2]; + uint32 ItemId; + uint32 SenderCreatureId; + std::string Subject; + std::string Body; + uint32 MailTemplateId; }; -typedef std::unordered_map<uint32, ModifierTreeNode*> ModifierTreeMap; - -enum AchievementCriteriaFlagsCu +struct AchievementRewardLocale { - ACHIEVEMENT_CRITERIA_FLAG_CU_PLAYER = 0x1, - ACHIEVEMENT_CRITERIA_FLAG_CU_ACCOUNT = 0x2, - ACHIEVEMENT_CRITERIA_FLAG_CU_GUILD = 0x4 + std::vector<std::string> Subject; + std::vector<std::string> Body; }; -struct AchievementCriteria +struct CompletedAchievementData { - uint32 ID = 0; - CriteriaEntry const* Entry = nullptr; - ModifierTreeNode const* Modifier = nullptr; - uint32 FlagsCu = 0; + std::time_t Date = std::time_t(0); + GuidSet CompletingPlayers; + bool Changed; }; -typedef std::vector<AchievementCriteria const*> AchievementCriteriaList; -typedef std::unordered_map<uint32, AchievementCriteria*> AchievementCriteriaMap; - -struct AchievementCriteriaTree +class TC_GAME_API AchievementMgr : public CriteriaHandler { - uint32 ID = 0; - CriteriaTreeEntry const* Entry = nullptr; - AchievementEntry const* Achievement = nullptr; - AchievementCriteria const* Criteria = nullptr; - std::vector<AchievementCriteriaTree const*> Children; -}; +public: + AchievementMgr(); + ~AchievementMgr(); -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; + void CheckAllAchievementCriteria(Player* referencePlayer); -typedef std::unordered_map<uint32, AchievementEntryList> AchievementListByReferencedId; + virtual void CompletedAchievement(AchievementEntry const* entry, Player* referencePlayer) = 0; + bool HasAchieved(uint32 achievementId) const; + uint32 GetAchievementPoints() const; -struct CriteriaProgress -{ - uint64 counter = 0; - time_t date = time_t(0); // latest update time. - ObjectGuid PlayerGUID; // GUID of the player that last updated the criteria - bool changed = false; -}; +protected: + bool CanUpdateCriteriaTree(Criteria const* criteria, CriteriaTree const* tree, Player* referencePlayer) const override; + bool CanCompleteCriteriaTree(CriteriaTree const* tree) override; + void CompletedCriteriaTree(CriteriaTree const* tree, Player* referencePlayer) override; + void AfterCriteriaTreeUpdate(CriteriaTree const* tree, Player* referencePlayer) override; -enum AchievementCriteriaDataType -{ // value1 value2 comment - ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE = 0, // 0 0 - ACHIEVEMENT_CRITERIA_DATA_TYPE_T_CREATURE = 1, // creature_id 0 - ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE = 2, // class_id race_id - ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_LESS_HEALTH= 3, // health_percent 0 - ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA = 5, // spell_id effect_idx - ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA = 7, // spell_id effect_idx - ACHIEVEMENT_CRITERIA_DATA_TYPE_VALUE = 8, // minvalue value provided with achievement update must be not less that limit - ACHIEVEMENT_CRITERIA_DATA_TYPE_T_LEVEL = 9, // minlevel minlevel of target - ACHIEVEMENT_CRITERIA_DATA_TYPE_T_GENDER = 10, // gender 0=male; 1=female - ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT = 11, // scripted requirement - // REUSE - ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT = 13, // count "with less than %u people in the zone" - ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM = 14, // team HORDE(67), ALLIANCE(469) - ACHIEVEMENT_CRITERIA_DATA_TYPE_S_DRUNK = 15, // drunken_state 0 (enum DrunkenState) of player - ACHIEVEMENT_CRITERIA_DATA_TYPE_HOLIDAY = 16, // holiday_id 0 event in holiday time - ACHIEVEMENT_CRITERIA_DATA_TYPE_BG_LOSS_TEAM_SCORE = 17, // min_score max_score player's team win bg and opposition team have team score in range - ACHIEVEMENT_CRITERIA_DATA_TYPE_INSTANCE_SCRIPT = 18, // 0 0 maker instance script call for check current criteria requirements fit - ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPED_ITEM = 19, // item_level item_quality for equipped item in slot to check item level and quality - ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_ID = 20, // map_id 0 player must be on map with id in map_id - ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE = 21, // class_id race_id - // REUSE - ACHIEVEMENT_CRITERIA_DATA_TYPE_S_KNOWN_TITLE = 23, // title_id known (pvp) title, values from dbc - ACHIEVEMENT_CRITERIA_DATA_TYPE_GAME_EVENT = 24, // game_event_id 0 - - MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE -}; + bool IsCompletedAchievement(AchievementEntry const* entry); -struct AchievementCriteriaData -{ - AchievementCriteriaDataType dataType; - union - { - // ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE = 0 (no data) - // ACHIEVEMENT_CRITERIA_DATA_TYPE_T_CREATURE = 1 - struct - { - uint32 id; - } creature; - // ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE = 2 - // ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE = 21 - struct - { - uint32 class_id; - uint32 race_id; - } classRace; - // ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_LESS_HEALTH = 3 - struct - { - uint32 percent; - } health; - // ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA = 5 - // ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA = 7 - struct - { - uint32 spell_id; - uint32 effect_idx; - } aura; - // ACHIEVEMENT_CRITERIA_DATA_TYPE_VALUE = 8 - struct - { - uint32 value; - uint32 compType; - } value; - // ACHIEVEMENT_CRITERIA_DATA_TYPE_T_LEVEL = 9 - struct - { - uint32 minlevel; - } level; - // ACHIEVEMENT_CRITERIA_DATA_TYPE_T_GENDER = 10 - struct - { - uint32 gender; - } gender; - // ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT = 11 (no data) - // ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT = 13 - struct - { - uint32 maxcount; - } map_players; - // ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM = 14 - struct - { - uint32 team; - } team; - // ACHIEVEMENT_CRITERIA_DATA_TYPE_S_DRUNK = 15 - struct - { - uint32 state; - } drunk; - // ACHIEVEMENT_CRITERIA_DATA_TYPE_HOLIDAY = 16 - struct - { - uint32 id; - } holiday; - // ACHIEVEMENT_CRITERIA_DATA_TYPE_BG_LOSS_TEAM_SCORE= 17 - struct - { - uint32 min_score; - uint32 max_score; - } bg_loss_team_score; - // ACHIEVEMENT_CRITERIA_DATA_TYPE_INSTANCE_SCRIPT = 18 (no data) - // ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPED_ITEM = 19 - struct - { - uint32 item_level; - uint32 item_quality; - } equipped_item; - // ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_ID = 20 - struct - { - uint32 mapId; - } map_id; - // ACHIEVEMENT_CRITERIA_DATA_TYPE_KNOWN_TITLE = 22 - struct - { - uint32 title_id; - } known_title; - // ACHIEVEMENT_CRITERIA_DATA_TYPE_GAME_EVENT = 24 - struct - { - uint32 id; - } game_event; - // raw - struct - { - uint32 value1; - uint32 value2; - } raw; - }; - uint32 ScriptId; - - AchievementCriteriaData() : dataType(ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE) - { - raw.value1 = 0; - raw.value2 = 0; - ScriptId = 0; - } - - AchievementCriteriaData(uint32 _dataType, uint32 _value1, uint32 _value2, uint32 _scriptId) : dataType(AchievementCriteriaDataType(_dataType)) - { - raw.value1 = _value1; - raw.value2 = _value2; - ScriptId = _scriptId; - } - - bool IsValid(AchievementCriteria const* criteria); - bool Meets(uint32 criteria_id, Player const* source, Unit const* target, uint32 miscValue1 = 0) const; -}; + bool RequiredAchievementSatisfied(uint32 achievementId) const override; -struct TC_GAME_API AchievementCriteriaDataSet -{ - AchievementCriteriaDataSet() : criteria_id(0) { } - typedef std::vector<AchievementCriteriaData> Storage; - void Add(AchievementCriteriaData const& data) { storage.push_back(data); } - bool Meets(Player const* source, Unit const* target, uint32 miscValue = 0) const; - void SetCriteriaId(uint32 id) {criteria_id = id;} - private: - uint32 criteria_id; - Storage storage; +protected: + std::unordered_map<uint32, CompletedAchievementData> _completedAchievements; + uint32 _achievementPoints; }; -typedef std::map<uint32, AchievementCriteriaDataSet> AchievementCriteriaDataMap; - -struct AchievementReward +class TC_GAME_API PlayerAchievementMgr : public AchievementMgr { - uint32 titleId[2]; - uint32 itemId; - uint32 sender; - std::string subject; - std::string text; - uint32 mailTemplate; -}; +public: + explicit PlayerAchievementMgr(Player* owner); -typedef std::unordered_map<uint32, AchievementReward> AchievementRewards; + void Reset() override; -struct AchievementRewardLocale -{ - std::vector<std::string> subject; - std::vector<std::string> text; -}; + static void DeleteFromDB(ObjectGuid const& guid); + void LoadFromDB(PreparedQueryResult achievementResult, PreparedQueryResult criteriaResult); + void SaveToDB(SQLTransaction& trans); -typedef std::unordered_map<uint32, AchievementRewardLocale> AchievementRewardLocales; + void ResetCriteria(CriteriaTypes type, uint64 miscValue1 = 0, uint64 miscValue2 = 0, bool evenIfCriteriaComplete = false); -struct CompletedAchievementData -{ - time_t date; - GuidSet guids; - bool changed; -}; + void SendAllData(Player const* receiver) const override; + void SendAchievementInfo(Player* receiver, uint32 achievementId = 0) const; -typedef std::unordered_map<uint32, CriteriaProgress> CriteriaProgressMap; -typedef std::unordered_map<uint32, CompletedAchievementData> CompletedAchievementMap; + void CompletedAchievement(AchievementEntry const* entry, Player* referencePlayer); -enum ProgressType -{ - PROGRESS_SET, - PROGRESS_ACCUMULATE, - PROGRESS_HIGHEST -}; +protected: + void SendCriteriaUpdate(Criteria const* entry, CriteriaProgress const* progress, uint32 timeElapsed, bool timedCompleted) const override; + void SendCriteriaProgressRemoved(uint32 criteriaId) override; -// Hackfix to solve an unresolved issue in clang that the visibility -// flag is ignored in some explicit template specializations, -// which prevents clang from exporting the `DeleteFromDB` symbol. -// https://llvm.org/bugs/show_bug.cgi?id=24815 -// https://llvm.org/bugs/show_bug.cgi?id=23667 -TC_GAME_API void DeletePlayerAchievementsFromDB(ObjectGuid guid); -TC_GAME_API void DeleteGuildAchievementsFromDB(ObjectGuid guid); + void SendAchievementEarned(AchievementEntry const* achievement) const; -template<typename T> -struct AchievementMgrDeleterBase; + void SendPacket(WorldPacket const* data) const; -template<> -struct AchievementMgrDeleterBase<Player> -{ - static void DeleteFromDB(ObjectGuid lowguid) { DeletePlayerAchievementsFromDB(lowguid); } -}; + std::string GetOwnerInfo() const override; + CriteriaList const& GetCriteriaByType(CriteriaTypes type) const override; -template<> -struct AchievementMgrDeleterBase<Guild> -{ - static void DeleteFromDB(ObjectGuid lowguid) { DeleteGuildAchievementsFromDB(lowguid); } +private: + Player* _owner; }; -template<class T> -class TC_GAME_API AchievementMgr - : public AchievementMgrDeleterBase<T> +class TC_GAME_API GuildAchievementMgr : public AchievementMgr { - public: - AchievementMgr(T* owner); - ~AchievementMgr(); - - void Reset(); - - using AchievementMgrDeleterBase<T>::DeleteFromDB; - - void LoadFromDB(PreparedQueryResult achievementResult, PreparedQueryResult criteriaResult); - void SaveToDB(SQLTransaction& trans); - void ResetAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1 = 0, uint64 miscValue2 = 0, bool evenIfCriteriaComplete = false); - void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1 = 0, uint64 miscValue2 = 0, uint64 miscValue3 = 0, Unit const* unit = NULL, Player* referencePlayer = NULL); - void CompletedAchievement(AchievementEntry const* entry, Player* referencePlayer); - void CheckAllAchievementCriteria(Player* referencePlayer); - void SendAllAchievementData(Player* receiver) const; - void SendAllTrackedCriterias(Player* receiver, std::set<uint32> const& trackedCriterias) const; - void SendAchievementInfo(Player* receiver, uint32 achievementId = 0) const; - bool HasAchieved(uint32 achievementId) const; - T* GetOwner() const { return _owner; } - - void UpdateTimedAchievements(uint32 timeDiff); - void StartTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry, uint32 timeLost = 0); - void RemoveTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry); // used for quest and scripted timed achievements - - uint32 GetAchievementPoints() const { return _achievementPoints; } - private: - void SendAchievementEarned(AchievementEntry const* achievement) const; - 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 IsCompletedCriteriaTree(AchievementCriteriaTree const* tree); - bool IsCompletedCriteria(AchievementCriteria const* achievementCriteria, uint64 requiredAmount); - bool IsCompletedAchievement(AchievementEntry const* entry); - 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(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 tree id/time left in MS - uint32 _achievementPoints; +public: + explicit GuildAchievementMgr(Guild* owner); + + void Reset() override; + + static void DeleteFromDB(ObjectGuid const& guid); + void LoadFromDB(PreparedQueryResult achievementResult, PreparedQueryResult criteriaResult); + void SaveToDB(SQLTransaction& trans); + + void SendAllData(Player const* receiver) const override; + void SendAchievementInfo(Player* receiver, uint32 achievementId = 0) const; + void SendAllTrackedCriterias(Player* receiver, std::set<uint32> const& trackedCriterias) const; + + void CompletedAchievement(AchievementEntry const* entry, Player* referencePlayer); + +protected: + void SendCriteriaUpdate(Criteria const* entry, CriteriaProgress const* progress, uint32 timeElapsed, bool timedCompleted) const override; + void SendCriteriaProgressRemoved(uint32 criteriaId) override; + + void SendAchievementEarned(AchievementEntry const* achievement) const; + + void SendPacket(WorldPacket const* data) const; + + std::string GetOwnerInfo() const override; + CriteriaList const& GetCriteriaByType(CriteriaTypes type) const override; + +private: + Guild* _owner; }; class TC_GAME_API AchievementGlobalMgr { - AchievementGlobalMgr() { } - ~AchievementGlobalMgr(); - - public: - static char const* GetCriteriaTypeString(AchievementCriteriaTypes type); - static char const* GetCriteriaTypeString(uint32 type); - - static AchievementGlobalMgr* instance(); - - AchievementCriteriaTreeList const* GetAchievementCriteriaTreesByCriteria(uint32 criteriaId) const - { - auto itr = _achievementCriteriaTreeByCriteria.find(criteriaId); - return itr != _achievementCriteriaTreeByCriteria.end() ? &itr->second : nullptr; - } - - AchievementCriteriaList const& GetAchievementCriteriaByType(AchievementCriteriaTypes type, bool guild = false) const - { - return guild ? _guildAchievementCriteriasByType[type] : _achievementCriteriasByType[type]; - } - - AchievementCriteriaList const& GetTimedAchievementCriteriaByType(AchievementCriteriaTimedTypes type) const - { - return _achievementCriteriasByTimedType[type]; - } - - AchievementEntryList const* GetAchievementByReferencedId(uint32 id) const - { - 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 = _achievementRewards.find(achievement->ID); - return iter != _achievementRewards.end() ? &iter->second : NULL; - } - - AchievementRewardLocale const* GetAchievementRewardLocale(AchievementEntry const* achievement) const - { - AchievementRewardLocales::const_iterator iter = _achievementRewardLocales.find(achievement->ID); - return iter != _achievementRewardLocales.end() ? &iter->second : NULL; - } - - AchievementCriteriaDataSet const* GetCriteriaDataSet(AchievementCriteria const* achievementCriteria) const - { - 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 = _allCompletedAchievements.find(achievement->ID); - if (itr == _allCompletedAchievements.end()) - return false; - - if (achievement->Flags & ACHIEVEMENT_FLAG_REALM_FIRST_KILL) - return itr->second != instanceId; - - return true; - } - - void SetRealmCompleted(AchievementEntry const* achievement, uint32 instanceId) - { - if (IsRealmCompleted(achievement, instanceId)) - return; - - _allCompletedAchievements[achievement->ID] = instanceId; - } - - bool IsGroupCriteriaType(AchievementCriteriaTypes type) const - { - switch (type) - { - case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE: - case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG: - case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET: // NYI - case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA: - case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2: // NYI - case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_BATTLEGROUND: // NYI - return true; - default: - break; - } - - return false; - } - - template<typename Func> - void WalkCriteriaTree(AchievementCriteriaTree const* tree, Func const& func) const - { - for (AchievementCriteriaTree const* node : tree->Children) - WalkCriteriaTree(node, func); - - func(tree); - } - - // Removes instanceId as valid id to complete realm first kill achievements - void OnInstanceDestroyed(uint32 instanceId); - - void LoadAchievementCriteriaModifiersTree(); - void LoadAchievementCriteriaList(); - void LoadAchievementCriteriaData(); - void LoadAchievementReferenceList(); - void LoadCompletedAchievements(); - void LoadRewards(); - void LoadRewardLocales(); - AchievementEntry const* GetAchievement(uint32 achievementId) const; - AchievementCriteriaTree const* GetAchievementCriteriaTree(uint32 criteriaTreeId) const; - AchievementCriteria const* GetAchievementCriteria(uint32 criteriaId) const; - private: - AchievementCriteriaDataMap _criteriaDataMap; - - AchievementCriteriaTreeMap _achievementCriteriaTrees; - AchievementCriteriaMap _achievementCriteria; - ModifierTreeMap _criteriaModifiers; - - AchievementCriteriaTreeByCriteriaMap _achievementCriteriaTreeByCriteria; - - // store achievement criterias by type to speed up lookup - AchievementCriteriaList _achievementCriteriasByType[ACHIEVEMENT_CRITERIA_TYPE_TOTAL]; - AchievementCriteriaList _guildAchievementCriteriasByType[ACHIEVEMENT_CRITERIA_TYPE_TOTAL]; - - AchievementCriteriaList _achievementCriteriasByTimedType[ACHIEVEMENT_TIMED_TYPE_MAX]; - - // store achievements by referenced achievement id to speed up lookup - AchievementListByReferencedId _achievementListByReferencedId; - - typedef std::map<uint32 /*achievementId*/, uint32 /*instanceId*/> AllCompletedAchievements; - AllCompletedAchievements _allCompletedAchievements; - - AchievementRewards _achievementRewards; - AchievementRewardLocales _achievementRewardLocales; + AchievementGlobalMgr() { } + ~AchievementGlobalMgr() { } + +public: + static AchievementGlobalMgr* Instance(); + + std::vector<AchievementEntry const*> const* GetAchievementByReferencedId(uint32 id) const; + AchievementReward const* GetAchievementReward(AchievementEntry const* achievement) const; + AchievementRewardLocale const* GetAchievementRewardLocale(AchievementEntry const* achievement) const; + + bool IsRealmCompleted(AchievementEntry const* achievement) const; + void SetRealmCompleted(AchievementEntry const* achievement); + + void LoadAchievementReferenceList(); + void LoadCompletedAchievements(); + void LoadRewards(); + void LoadRewardLocales(); + +private: + // store achievements by referenced achievement id to speed up lookup + std::unordered_map<uint32, std::vector<AchievementEntry const*>> _achievementListByReferencedId; + + // store realm first achievements + // std::chrono::system_clock::time_point::min() is a placeholder value for realm firsts not yet completed + // std::chrono::system_clock::time_point::max() is a value assigned to realm firsts complete before worldserver started + std::unordered_map<uint32 /*achievementId*/, std::chrono::system_clock::time_point /*completionTime*/> _allCompletedAchievements; + + std::unordered_map<uint32, AchievementReward> _achievementRewards; + std::unordered_map<uint32, AchievementRewardLocale> _achievementRewardLocales; }; -#define sAchievementMgr AchievementGlobalMgr::instance() +#define sAchievementMgr AchievementGlobalMgr::Instance() #endif diff --git a/src/server/game/Achievements/CriteriaHandler.cpp b/src/server/game/Achievements/CriteriaHandler.cpp new file mode 100644 index 00000000000..4bd51eb6d79 --- /dev/null +++ b/src/server/game/Achievements/CriteriaHandler.cpp @@ -0,0 +1,2218 @@ +/* + * Copyright (C) 2008-2016 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 "CriteriaHandler.h" +#include "ArenaTeamMgr.h" +#include "Battleground.h" +#include "DBCStores.h" +#include "DB2Stores.h" +#include "DisableMgr.h" +#include "GameEventMgr.h" +#include "Garrison.h" +#include "Group.h" +#include "InstanceScript.h" +#include "MapManager.h" +#include "ObjectMgr.h" +#include "Player.h" +#include "ReputationMgr.h" +#include "ScriptMgr.h" +#include "SpellInfo.h" +#include "SpellMgr.h" + +bool CriteriaData::IsValid(Criteria const* criteria) +{ + if (DataType >= MAX_CRITERIA_DATA_TYPE) + { + TC_LOG_ERROR("sql.sql", "Table `criteria_data` for criteria (Entry: %u) contains a wrong data type (%u), ignored.", criteria->ID, DataType); + return false; + } + + switch (criteria->Entry->Type) + { + case CRITERIA_TYPE_KILL_CREATURE: + case CRITERIA_TYPE_KILL_CREATURE_TYPE: + case CRITERIA_TYPE_WIN_BG: + case CRITERIA_TYPE_FALL_WITHOUT_DYING: + case CRITERIA_TYPE_COMPLETE_QUEST: // only hardcoded list + case CRITERIA_TYPE_CAST_SPELL: + case CRITERIA_TYPE_WIN_RATED_ARENA: + case CRITERIA_TYPE_DO_EMOTE: + case CRITERIA_TYPE_SPECIAL_PVP_KILL: + case CRITERIA_TYPE_WIN_DUEL: + case CRITERIA_TYPE_LOOT_TYPE: + case CRITERIA_TYPE_CAST_SPELL2: + case CRITERIA_TYPE_BE_SPELL_TARGET: + case CRITERIA_TYPE_BE_SPELL_TARGET2: + case CRITERIA_TYPE_EQUIP_EPIC_ITEM: + case CRITERIA_TYPE_ROLL_NEED_ON_LOOT: + case CRITERIA_TYPE_ROLL_GREED_ON_LOOT: + case CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE: + case CRITERIA_TYPE_HONORABLE_KILL: + case CRITERIA_TYPE_COMPLETE_DAILY_QUEST: // only Children's Week achievements + case CRITERIA_TYPE_USE_ITEM: // only Children's Week achievements + case CRITERIA_TYPE_GET_KILLING_BLOWS: + case CRITERIA_TYPE_REACH_LEVEL: + case CRITERIA_TYPE_ON_LOGIN: + break; + default: + if (DataType != CRITERIA_DATA_TYPE_SCRIPT) + { + TC_LOG_ERROR("sql.sql", "Table `criteria_data` contains data for a non-supported criteria type (Entry: %u Type: %u), ignored.", criteria->ID, criteria->Entry->Type); + return false; + } + break; + } + + switch (DataType) + { + case CRITERIA_DATA_TYPE_NONE: + case CRITERIA_DATA_TYPE_INSTANCE_SCRIPT: + return true; + case CRITERIA_DATA_TYPE_T_CREATURE: + if (!Creature.Id || !sObjectMgr->GetCreatureTemplate(Creature.Id)) + { + TC_LOG_ERROR("sql.sql", "Table `criteria_data` (Entry: %u Type: %u) for data type CRITERIA_DATA_TYPE_CREATURE (%u) contains a non-existing creature id in value1 (%u), ignored.", + criteria->ID, criteria->Entry->Type, DataType, Creature.Id); + return false; + } + return true; + case CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE: + if (!ClassRace.Class && !ClassRace.Race) + { + TC_LOG_ERROR("sql.sql", "Table `criteria_data` (Entry: %u Type: %u) for data type CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE (%u) must not have 0 in either value field, ignored.", + criteria->ID, criteria->Entry->Type, DataType); + return false; + } + if (ClassRace.Class && ((1 << (ClassRace.Class-1)) & CLASSMASK_ALL_PLAYABLE) == 0) + { + TC_LOG_ERROR("sql.sql", "Table `criteria_data` (Entry: %u Type: %u) for data type CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE (%u) contains a non-existing class in value1 (%u), ignored.", + criteria->ID, criteria->Entry->Type, DataType, ClassRace.Class); + return false; + } + if (ClassRace.Race && ((1 << (ClassRace.Race-1)) & RACEMASK_ALL_PLAYABLE) == 0) + { + TC_LOG_ERROR("sql.sql", "Table `criteria_data` (Entry: %u Type: %u) for data type CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE (%u) contains a non-existing race in value2 (%u), ignored.", + criteria->ID, criteria->Entry->Type, DataType, ClassRace.Race); + return false; + } + return true; + case CRITERIA_DATA_TYPE_T_PLAYER_LESS_HEALTH: + if (Health.Percent < 1 || Health.Percent > 100) + { + TC_LOG_ERROR("sql.sql", "Table `criteria_data` (Entry: %u Type: %u) for data type CRITERIA_DATA_TYPE_PLAYER_LESS_HEALTH (%u) contains a wrong percent value in value1 (%u), ignored.", + criteria->ID, criteria->Entry->Type, DataType, Health.Percent); + return false; + } + return true; + case CRITERIA_DATA_TYPE_S_AURA: + case CRITERIA_DATA_TYPE_T_AURA: + { + SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(Aura.SpellId); + if (!spellEntry) + { + TC_LOG_ERROR("sql.sql", "Table `criteria_data` (Entry: %u Type: %u) for data type %s (%u) contains a wrong spell id in value1 (%u), ignored.", + criteria->ID, criteria->Entry->Type, (DataType == CRITERIA_DATA_TYPE_S_AURA ? "CRITERIA_DATA_TYPE_S_AURA" : "CRITERIA_DATA_TYPE_T_AURA"), DataType, Aura.SpellId); + return false; + } + SpellEffectInfo const* effect = spellEntry->GetEffect(DIFFICULTY_NONE, Aura.EffectIndex); + if (!effect) + { + TC_LOG_ERROR("sql.sql", "Table `criteria_data` (Entry: %u Type: %u) for data type %s (%u) contains a wrong spell effect index in value2 (%u), ignored.", + criteria->ID, criteria->Entry->Type, (DataType == CRITERIA_DATA_TYPE_S_AURA ? "CRITERIA_DATA_TYPE_S_AURA" : "CRITERIA_DATA_TYPE_T_AURA"), DataType, Aura.EffectIndex); + return false; + } + if (!effect->ApplyAuraName) + { + TC_LOG_ERROR("sql.sql", "Table `criteria_data` (Entry: %u Type: %u) for data type %s (%u) contains a non-aura spell effect (ID: %u Effect: %u), ignored.", + criteria->ID, criteria->Entry->Type, (DataType == CRITERIA_DATA_TYPE_S_AURA ? "CRITERIA_DATA_TYPE_S_AURA" : "CRITERIA_DATA_TYPE_T_AURA"), DataType, Aura.SpellId, Aura.EffectIndex); + return false; + } + return true; + } + case CRITERIA_DATA_TYPE_VALUE: + if (Value.ComparisonType >= COMP_TYPE_MAX) + { + TC_LOG_ERROR("sql.sql", "Table `criteria_data` (Entry: %u Type: %u) for data type CRITERIA_DATA_TYPE_VALUE (%u) contains a wrong ComparisionType in value2 (%u), ignored.", + criteria->ID, criteria->Entry->Type, DataType, Value.ComparisonType); + return false; + } + return true; + case CRITERIA_DATA_TYPE_T_LEVEL: + if (Level.Min > STRONG_MAX_LEVEL) + { + TC_LOG_ERROR("sql.sql", "Table `CRITERIA_DATA` (Entry: %u Type: %u) for data type CRITERIA_DATA_TYPE_T_LEVEL (%u) contains a wrong minlevel in value1 (%u), ignored.", + criteria->ID, criteria->Entry->Type, DataType, Level.Min); + return false; + } + return true; + case CRITERIA_DATA_TYPE_T_GENDER: + if (Gender.Gender > GENDER_NONE) + { + TC_LOG_ERROR("sql.sql", "Table `criteria_data` (Entry: %u Type: %u) for data type CRITERIA_DATA_TYPE_T_GENDER (%u) contains a wrong gender value in value1 (%u), ignored.", + criteria->ID, criteria->Entry->Type, DataType, Gender.Gender); + return false; + } + return true; + case CRITERIA_DATA_TYPE_SCRIPT: + if (!ScriptId) + { + TC_LOG_ERROR("sql.sql", "Table `criteria_data` (Entry: %u Type: %u) for data type CRITERIA_DATA_TYPE_SCRIPT (%u) does not have a ScriptName set, ignored.", + criteria->ID, criteria->Entry->Type, DataType); + return false; + } + return true; + case CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT: + if (MapPlayers.MaxCount <= 0) + { + TC_LOG_ERROR("sql.sql", "Table `criteria_data` (Entry: %u Type: %u) for data type CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT (%u) contains a wrong max players count in value1 (%u), ignored.", + criteria->ID, criteria->Entry->Type, DataType, MapPlayers.MaxCount); + return false; + } + return true; + case CRITERIA_DATA_TYPE_T_TEAM: + if (Team.Team != ALLIANCE && Team.Team != HORDE) + { + TC_LOG_ERROR("sql.sql", "Table `criteria_data` (Entry: %u Type: %u) for data type CRITERIA_DATA_TYPE_T_TEAM (%u) contains an unknown team value in value1 (%u), ignored.", + criteria->ID, criteria->Entry->Type, DataType, Team.Team); + return false; + } + return true; + case CRITERIA_DATA_TYPE_S_DRUNK: + if (Drunk.State >= MAX_DRUNKEN) + { + TC_LOG_ERROR("sql.sql", "Table `criteria_data` (Entry: %u Type: %u) for data type CRITERIA_DATA_TYPE_S_DRUNK (%u) contains an unknown drunken state value in value1 (%u), ignored.", + criteria->ID, criteria->Entry->Type, DataType, Drunk.State); + return false; + } + return true; + case CRITERIA_DATA_TYPE_HOLIDAY: + if (!sHolidaysStore.LookupEntry(Holiday.Id)) + { + TC_LOG_ERROR("sql.sql", "Table `criteria_data` (Entry: %u Type: %u) for data type CRITERIA_DATA_TYPE_HOLIDAY (%u) contains an unknown holiday entry in value1 (%u), ignored.", + criteria->ID, criteria->Entry->Type, DataType, Holiday.Id); + return false; + } + return true; + case CRITERIA_DATA_TYPE_GAME_EVENT: + { + GameEventMgr::GameEventDataMap const& events = sGameEventMgr->GetEventMap(); + if (GameEvent.Id < 1 || GameEvent.Id >= events.size()) + { + TC_LOG_ERROR("sql.sql", "Table `criteria_data` (Entry: %u Type: %u) for data type CRITERIA_DATA_TYPE_GAME_EVENT (%u) has unknown game_event in value1 (%u), ignored.", + criteria->ID, criteria->Entry->Type, DataType, GameEvent.Id); + return false; + } + return true; + } + case CRITERIA_DATA_TYPE_BG_LOSS_TEAM_SCORE: + return true; // not check correctness node indexes + case CRITERIA_DATA_TYPE_S_EQUIPED_ITEM: + if (EquippedItem.Quality >= MAX_ITEM_QUALITY) + { + TC_LOG_ERROR("sql.sql", "Table `criteria_data` (Entry: %u Type: %u) for data type CRITERIA_DATA_TYPE_S_EQUIPED_ITEM (%u) contains an unknown quality state value in value1 (%u), ignored.", + criteria->ID, criteria->Entry->Type, DataType, EquippedItem.Quality); + return false; + } + return true; + case CRITERIA_DATA_TYPE_MAP_ID: + if (!sMapStore.LookupEntry(Map.Id)) + { + TC_LOG_ERROR("sql.sql", "Table `criteria_data` (Entry: %u Type: %u) for data type CRITERIA_DATA_TYPE_MAP_ID (%u) contains an unknown map entry in value1 (%u), ignored.", + criteria->ID, criteria->Entry->Type, DataType, Map.Id); + } + return true; + case CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE: + if (!ClassRace.Class && !ClassRace.Race) + { + TC_LOG_ERROR("sql.sql", "Table `criteria_data` (Entry: %u Type: %u) for data type CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE (%u) should not have 0 in either value field. Ignored.", + criteria->ID, criteria->Entry->Type, DataType); + return false; + } + if (ClassRace.Class && ((1 << (ClassRace.Class-1)) & CLASSMASK_ALL_PLAYABLE) == 0) + { + TC_LOG_ERROR("sql.sql", "Table `criteria_data` (Entry: %u Type: %u) for data type CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE (%u) contains a non-existing class entry in value1 (%u), ignored.", + criteria->ID, criteria->Entry->Type, DataType, ClassRace.Class); + return false; + } + if (ClassRace.Race && ((1 << (ClassRace.Race-1)) & RACEMASK_ALL_PLAYABLE) == 0) + { + TC_LOG_ERROR("sql.sql", "Table `criteria_data` (Entry: %u Type: %u) for data type CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE (%u) contains a non-existing race entry in value2 (%u), ignored.", + criteria->ID, criteria->Entry->Type, DataType, ClassRace.Race); + return false; + } + return true; + case CRITERIA_DATA_TYPE_S_KNOWN_TITLE: + if (!sCharTitlesStore.LookupEntry(KnownTitle.Id)) + { + TC_LOG_ERROR("sql.sql", "Table `criteria_data` (Entry: %u Type: %u) for data type CRITERIA_DATA_TYPE_S_KNOWN_TITLE (%u) contains an unknown title_id in value1 (%u), ignore.", + criteria->ID, criteria->Entry->Type, DataType, KnownTitle.Id); + return false; + } + return true; + default: + TC_LOG_ERROR("sql.sql", "Table `criteria_data` (Entry: %u Type: %u) contains data of a non-supported data type (%u), ignored.", criteria->ID, criteria->Entry->Type, DataType); + return false; + } +} + +bool CriteriaData::Meets(uint32 criteriaId, Player const* source, Unit const* target, uint32 miscValue1 /*= 0*/) const +{ + switch (DataType) + { + case CRITERIA_DATA_TYPE_NONE: + return true; + case CRITERIA_DATA_TYPE_T_CREATURE: + if (!target || target->GetTypeId() != TYPEID_UNIT) + return false; + return target->GetEntry() == Creature.Id; + case CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE: + if (!target || target->GetTypeId() != TYPEID_PLAYER) + return false; + if (ClassRace.Class && ClassRace.Class != target->ToPlayer()->getClass()) + return false; + if (ClassRace.Race && ClassRace.Race != target->ToPlayer()->getRace()) + return false; + return true; + case CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE: + if (source->GetTypeId() != TYPEID_PLAYER) + return false; + if (ClassRace.Class && ClassRace.Class != source->ToPlayer()->getClass()) + return false; + if (ClassRace.Race && ClassRace.Race != source->ToPlayer()->getRace()) + return false; + return true; + case CRITERIA_DATA_TYPE_T_PLAYER_LESS_HEALTH: + if (!target || target->GetTypeId() != TYPEID_PLAYER) + return false; + return !target->HealthAbovePct(Health.Percent); + case CRITERIA_DATA_TYPE_S_AURA: + return source->HasAuraEffect(Aura.SpellId, uint8(Aura.EffectIndex)); + case CRITERIA_DATA_TYPE_T_AURA: + return target && target->HasAuraEffect(Aura.SpellId, uint8(Aura.EffectIndex)); + case CRITERIA_DATA_TYPE_VALUE: + return CompareValues(ComparisionType(Value.ComparisonType), miscValue1, Value.Value); + case CRITERIA_DATA_TYPE_T_LEVEL: + if (!target) + return false; + return target->getLevel() >= Level.Min; + case CRITERIA_DATA_TYPE_T_GENDER: + if (!target) + return false; + return target->getGender() == Gender.Gender; + case CRITERIA_DATA_TYPE_SCRIPT: + return sScriptMgr->OnCriteriaCheck(ScriptId, const_cast<Player*>(source), const_cast<Unit*>(target)); + case CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT: + return source->GetMap()->GetPlayersCountExceptGMs() <= MapPlayers.MaxCount; + case CRITERIA_DATA_TYPE_T_TEAM: + if (!target || target->GetTypeId() != TYPEID_PLAYER) + return false; + return target->ToPlayer()->GetTeam() == Team.Team; + case CRITERIA_DATA_TYPE_S_DRUNK: + return Player::GetDrunkenstateByValue(source->GetDrunkValue()) >= DrunkenState(Drunk.State); + case CRITERIA_DATA_TYPE_HOLIDAY: + return IsHolidayActive(HolidayIds(Holiday.Id)); + case CRITERIA_DATA_TYPE_GAME_EVENT: + return IsEventActive(uint16(GameEvent.Id)); + case CRITERIA_DATA_TYPE_BG_LOSS_TEAM_SCORE: + { + Battleground* bg = source->GetBattleground(); + if (!bg) + return false; + + uint32 score = bg->GetTeamScore(source->GetTeamId() == TEAM_ALLIANCE ? TEAM_HORDE : TEAM_ALLIANCE); + return score >= BattlegroundScore.Min && score <= BattlegroundScore.Max; + } + case CRITERIA_DATA_TYPE_INSTANCE_SCRIPT: + { + if (!source->IsInWorld()) + return false; + class Map* map = source->GetMap(); + if (!map->IsDungeon()) + { + TC_LOG_ERROR("criteria", "Criteria system call CRITERIA_DATA_TYPE_INSTANCE_SCRIPT (%u) for criteria %u in a non-dungeon/non-raid map %u", + DataType, criteriaId, map->GetId()); + return false; + } + InstanceScript* instance = map->ToInstanceMap()->GetInstanceScript(); + if (!instance) + { + TC_LOG_ERROR("criteria", "Criteria system call CRITERIA_DATA_TYPE_INSTANCE_SCRIPT (%u) for criteria %u in map %u, but the map does not have an instance script.", + DataType, criteriaId, map->GetId()); + return false; + } + return instance->CheckAchievementCriteriaMeet(criteriaId, source, target, miscValue1); + } + case CRITERIA_DATA_TYPE_S_EQUIPED_ITEM: + { + ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(miscValue1); + if (!pProto) + return false; + return pProto->GetBaseItemLevel() >= EquippedItem.ItemLevel && pProto->GetQuality() >= EquippedItem.Quality; + } + case CRITERIA_DATA_TYPE_MAP_ID: + return source->GetMapId() == Map.Id; + case CRITERIA_DATA_TYPE_S_KNOWN_TITLE: + { + if (CharTitlesEntry const* titleInfo = sCharTitlesStore.LookupEntry(KnownTitle.Id)) + return source && source->HasTitle(titleInfo->MaskID); + + return false; + } + default: + break; + } + return false; +} + +bool CriteriaDataSet::Meets(Player const* source, Unit const* target, uint32 miscValue /*= 0*/) const +{ + for (CriteriaData const& data : _storage) + if (!data.Meets(_criteriaId, source, target, miscValue)) + return false; + + return true; +} + +CriteriaHandler::CriteriaHandler() { } + +CriteriaHandler::~CriteriaHandler() { } + +void CriteriaHandler::Reset() +{ + for (auto iter = _criteriaProgress.begin(); iter != _criteriaProgress.end(); ++iter) + SendCriteriaProgressRemoved(iter->first); + + _criteriaProgress.clear(); +} + +/** + * this function will be called whenever the user might have done a criteria relevant action + */ +void CriteriaHandler::UpdateCriteria(CriteriaTypes type, uint64 miscValue1 /*= 0*/, uint64 miscValue2 /*= 0*/, uint64 miscValue3 /*= 0*/, Unit const* unit /*= nullptr*/, Player* referencePlayer /*= nullptr*/) +{ + if (type >= CRITERIA_TYPE_TOTAL) + { + TC_LOG_DEBUG("criteria", "CriteriaHandler::UpdateCriteria: Wrong criteria type %u", type); + return; + } + + if (!referencePlayer) + { + TC_LOG_DEBUG("criteria", "CriteriaHandler::UpdateCriteria: Player is NULL! Cant update criteria"); + return; + } + + // disable for gamemasters with GM-mode enabled + if (referencePlayer->IsGameMaster()) + { + TC_LOG_DEBUG("criteria", "CriteriaHandler::UpdateCriteria: [Player %s GM mode on] %s, %s (%u), " UI64FMTD ", " UI64FMTD ", " UI64FMTD, + referencePlayer->GetName().c_str(), GetOwnerInfo().c_str(), CriteriaMgr::GetCriteriaTypeString(type), type, miscValue1, miscValue2, miscValue3); + return; + } + + TC_LOG_DEBUG("criteria", "CriteriaHandler::UpdateCriteria(%s, " UI64FMTD ", " UI64FMTD ", " UI64FMTD ") %s", + CriteriaMgr::GetCriteriaTypeString(type), type, miscValue1, miscValue2, miscValue3, GetOwnerInfo().c_str()); + + CriteriaList const& criteriaList = GetCriteriaByType(type); + for (Criteria const* criteria : criteriaList) + { + CriteriaTreeList const* trees = sCriteriaMgr->GetCriteriaTreesByCriteria(criteria->ID); + if (!CanUpdateCriteria(criteria, trees, miscValue1, miscValue2, miscValue3, unit, referencePlayer)) + continue; + + // requirements not found in the dbc + if (CriteriaDataSet const* data = sCriteriaMgr->GetCriteriaDataSet(criteria)) + if (!data->Meets(referencePlayer, unit, uint32(miscValue1))) + continue; + + switch (type) + { + // std. case: increment at 1 + case CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS: + case CRITERIA_TYPE_LOSE_DUEL: + case CRITERIA_TYPE_CREATE_AUCTION: + case CRITERIA_TYPE_WON_AUCTIONS: /* FIXME: for online player only currently */ + case CRITERIA_TYPE_ROLL_NEED: + case CRITERIA_TYPE_ROLL_GREED: + case CRITERIA_TYPE_QUEST_ABANDONED: + case CRITERIA_TYPE_FLIGHT_PATHS_TAKEN: + case CRITERIA_TYPE_ACCEPTED_SUMMONINGS: + case CRITERIA_TYPE_LOOT_EPIC_ITEM: + case CRITERIA_TYPE_RECEIVE_EPIC_ITEM: + case CRITERIA_TYPE_DEATH: + case CRITERIA_TYPE_COMPLETE_DAILY_QUEST: + case CRITERIA_TYPE_DEATH_AT_MAP: + case CRITERIA_TYPE_DEATH_IN_DUNGEON: + case CRITERIA_TYPE_KILLED_BY_CREATURE: + case CRITERIA_TYPE_KILLED_BY_PLAYER: + case CRITERIA_TYPE_DEATHS_FROM: + case CRITERIA_TYPE_BE_SPELL_TARGET: + case CRITERIA_TYPE_BE_SPELL_TARGET2: + case CRITERIA_TYPE_CAST_SPELL: + case CRITERIA_TYPE_CAST_SPELL2: + case CRITERIA_TYPE_WIN_RATED_ARENA: + case CRITERIA_TYPE_USE_ITEM: + case CRITERIA_TYPE_ROLL_NEED_ON_LOOT: + case CRITERIA_TYPE_ROLL_GREED_ON_LOOT: + case CRITERIA_TYPE_DO_EMOTE: + case CRITERIA_TYPE_USE_GAMEOBJECT: + case CRITERIA_TYPE_FISH_IN_GAMEOBJECT: + case CRITERIA_TYPE_WIN_DUEL: + case CRITERIA_TYPE_HK_CLASS: + case CRITERIA_TYPE_HK_RACE: + case CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE: + case CRITERIA_TYPE_HONORABLE_KILL: + case CRITERIA_TYPE_SPECIAL_PVP_KILL: + case CRITERIA_TYPE_GET_KILLING_BLOWS: + case CRITERIA_TYPE_HONORABLE_KILL_AT_AREA: + case CRITERIA_TYPE_WIN_ARENA: // This also behaves like CRITERIA_TYPE_WIN_RATED_ARENA + case CRITERIA_TYPE_ON_LOGIN: + case CRITERIA_TYPE_PLACE_GARRISON_BUILDING: + case CRITERIA_TYPE_OWN_BATTLE_PET_COUNT: + SetCriteriaProgress(criteria, 1, referencePlayer, PROGRESS_ACCUMULATE); + break; + // std case: increment at miscValue1 + case CRITERIA_TYPE_MONEY_FROM_VENDORS: + case CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS: + case CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD: + case CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING: + case CRITERIA_TYPE_GOLD_SPENT_AT_BARBER: + case CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL: + case CRITERIA_TYPE_LOOT_MONEY: + case CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS:/* FIXME: for online player only currently */ + case CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED: + case CRITERIA_TYPE_TOTAL_HEALING_RECEIVED: + case CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS: + case CRITERIA_TYPE_WIN_BG: + case CRITERIA_TYPE_COMPLETE_BATTLEGROUND: + case CRITERIA_TYPE_DAMAGE_DONE: + case CRITERIA_TYPE_HEALING_DONE: + SetCriteriaProgress(criteria, miscValue1, referencePlayer, PROGRESS_ACCUMULATE); + break; + case CRITERIA_TYPE_KILL_CREATURE: + case CRITERIA_TYPE_KILL_CREATURE_TYPE: + case CRITERIA_TYPE_LOOT_TYPE: + case CRITERIA_TYPE_OWN_ITEM: + case CRITERIA_TYPE_LOOT_ITEM: + case CRITERIA_TYPE_CURRENCY: + SetCriteriaProgress(criteria, miscValue2, referencePlayer, PROGRESS_ACCUMULATE); + break; + // std case: high value at miscValue1 + case CRITERIA_TYPE_HIGHEST_AUCTION_BID: + case CRITERIA_TYPE_HIGHEST_AUCTION_SOLD: /* FIXME: for online player only currently */ + case CRITERIA_TYPE_HIGHEST_HIT_DEALT: + case CRITERIA_TYPE_HIGHEST_HIT_RECEIVED: + case CRITERIA_TYPE_HIGHEST_HEAL_CAST: + case CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED: + SetCriteriaProgress(criteria, miscValue1, referencePlayer, PROGRESS_HIGHEST); + break; + case CRITERIA_TYPE_REACH_LEVEL: + SetCriteriaProgress(criteria, referencePlayer->getLevel(), referencePlayer); + break; + case CRITERIA_TYPE_REACH_SKILL_LEVEL: + if (uint32 skillvalue = referencePlayer->GetBaseSkillValue(criteria->Entry->Asset.SkillID)) + SetCriteriaProgress(criteria, skillvalue, referencePlayer); + break; + case CRITERIA_TYPE_LEARN_SKILL_LEVEL: + if (uint32 maxSkillvalue = referencePlayer->GetPureMaxSkillValue(criteria->Entry->Asset.SkillID)) + SetCriteriaProgress(criteria, maxSkillvalue, referencePlayer); + break; + case CRITERIA_TYPE_COMPLETE_QUEST_COUNT: + SetCriteriaProgress(criteria, referencePlayer->GetRewardedQuestCount(), referencePlayer); + break; + case CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY: + { + time_t nextDailyResetTime = sWorld->GetNextDailyQuestsResetTime(); + CriteriaProgress *progress = GetCriteriaProgress(criteria); + + if (!miscValue1) // Login case. + { + // reset if player missed one day. + if (progress && progress->Date < (nextDailyResetTime - 2 * DAY)) + SetCriteriaProgress(criteria, 0, referencePlayer, PROGRESS_SET); + continue; + } + + ProgressType progressType; + if (!progress) + // 1st time. Start count. + progressType = PROGRESS_SET; + else if (progress->Date < (nextDailyResetTime - 2 * DAY)) + // last progress is older than 2 days. Player missed 1 day => Restart count. + progressType = PROGRESS_SET; + else if (progress->Date < (nextDailyResetTime - DAY)) + // last progress is between 1 and 2 days. => 1st time of the day. + progressType = PROGRESS_ACCUMULATE; + else + // last progress is within the day before the reset => Already counted today. + continue; + + SetCriteriaProgress(criteria, 1, referencePlayer, progressType); + break; + } + case CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE: + { + uint32 counter = 0; + + const RewardedQuestSet &rewQuests = referencePlayer->getRewardedQuests(); + 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()) == criteria->Entry->Asset.ZoneID) + ++counter; + } + SetCriteriaProgress(criteria, counter, referencePlayer); + break; + } + case CRITERIA_TYPE_FALL_WITHOUT_DYING: + // miscValue1 is the ingame fallheight*100 as stored in dbc + SetCriteriaProgress(criteria, miscValue1, referencePlayer); + break; + case CRITERIA_TYPE_COMPLETE_QUEST: + case CRITERIA_TYPE_LEARN_SPELL: + case CRITERIA_TYPE_EXPLORE_AREA: + case CRITERIA_TYPE_VISIT_BARBER_SHOP: + case CRITERIA_TYPE_EQUIP_EPIC_ITEM: + case CRITERIA_TYPE_EQUIP_ITEM: + case CRITERIA_TYPE_COMPLETE_ACHIEVEMENT: + case CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER: + case CRITERIA_TYPE_OWN_BATTLE_PET: + SetCriteriaProgress(criteria, 1, referencePlayer); + break; + case CRITERIA_TYPE_BUY_BANK_SLOT: + SetCriteriaProgress(criteria, referencePlayer->GetBankBagSlotCount(), referencePlayer); + break; + case CRITERIA_TYPE_GAIN_REPUTATION: + { + int32 reputation = referencePlayer->GetReputationMgr().GetReputation(criteria->Entry->Asset.FactionID); + if (reputation > 0) + SetCriteriaProgress(criteria, reputation, referencePlayer); + break; + } + case CRITERIA_TYPE_GAIN_EXALTED_REPUTATION: + SetCriteriaProgress(criteria, referencePlayer->GetReputationMgr().GetExaltedFactionCount(), referencePlayer); + break; + case CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS: + case CRITERIA_TYPE_LEARN_SKILL_LINE: + { + uint32 spellCount = 0; + for (PlayerSpellMap::const_iterator spellIter = referencePlayer->GetSpellMap().begin(); + spellIter != referencePlayer->GetSpellMap().end(); + ++spellIter) + { + SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellIter->first); + for (SkillLineAbilityMap::const_iterator skillIter = bounds.first; skillIter != bounds.second; ++skillIter) + { + if (skillIter->second->SkillLine == criteria->Entry->Asset.SkillID) + spellCount++; + } + } + SetCriteriaProgress(criteria, spellCount, referencePlayer); + break; + } + case CRITERIA_TYPE_GAIN_REVERED_REPUTATION: + SetCriteriaProgress(criteria, referencePlayer->GetReputationMgr().GetReveredFactionCount(), referencePlayer); + break; + case CRITERIA_TYPE_GAIN_HONORED_REPUTATION: + SetCriteriaProgress(criteria, referencePlayer->GetReputationMgr().GetHonoredFactionCount(), referencePlayer); + break; + case CRITERIA_TYPE_KNOWN_FACTIONS: + SetCriteriaProgress(criteria, referencePlayer->GetReputationMgr().GetVisibleFactionCount(), referencePlayer); + break; + case CRITERIA_TYPE_EARN_HONORABLE_KILL: + SetCriteriaProgress(criteria, referencePlayer->GetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS), referencePlayer); + break; + case CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED: + SetCriteriaProgress(criteria, referencePlayer->GetMoney(), referencePlayer, PROGRESS_HIGHEST); + break; + case CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS: + if (!miscValue1) + continue; + SetCriteriaProgress(criteria, miscValue1, referencePlayer, PROGRESS_ACCUMULATE); + break; + case CRITERIA_TYPE_HIGHEST_PERSONAL_RATING: + { + uint32 reqTeamType = criteria->Entry->Asset.TeamType; + + if (miscValue1) + { + if (miscValue2 != reqTeamType) + continue; + + SetCriteriaProgress(criteria, miscValue1, referencePlayer, PROGRESS_HIGHEST); + } + else // login case + { + for (uint8 arena_slot = 0; arena_slot < MAX_ARENA_SLOT; ++arena_slot) + { + uint32 teamId = referencePlayer->GetArenaTeamId(arena_slot); + if (!teamId) + continue; + + ArenaTeam* team = sArenaTeamMgr->GetArenaTeamById(teamId); + if (!team || team->GetType() != reqTeamType) + continue; + + if (ArenaTeamMember const* member = team->GetMember(referencePlayer->GetGUID())) + { + SetCriteriaProgress(criteria, member->PersonalRating, referencePlayer, PROGRESS_HIGHEST); + break; + } + } + } + break; + } + case CRITERIA_TYPE_REACH_GUILD_LEVEL: + SetCriteriaProgress(criteria, miscValue1, referencePlayer); + break; + // FIXME: not triggered in code as result, need to implement + case CRITERIA_TYPE_COMPLETE_RAID: + case CRITERIA_TYPE_PLAY_ARENA: + case CRITERIA_TYPE_HIGHEST_TEAM_RATING: + case CRITERIA_TYPE_OWN_RANK: + case CRITERIA_TYPE_SPENT_GOLD_GUILD_REPAIRS: + case CRITERIA_TYPE_CRAFT_ITEMS_GUILD: + case CRITERIA_TYPE_CATCH_FROM_POOL: + case CRITERIA_TYPE_BUY_GUILD_BANK_SLOTS: + case CRITERIA_TYPE_EARN_GUILD_ACHIEVEMENT_POINTS: + case CRITERIA_TYPE_WIN_RATED_BATTLEGROUND: + case CRITERIA_TYPE_REACH_BG_RATING: + case CRITERIA_TYPE_BUY_GUILD_TABARD: + case CRITERIA_TYPE_COMPLETE_QUESTS_GUILD: + case CRITERIA_TYPE_HONORABLE_KILLS_GUILD: + case CRITERIA_TYPE_KILL_CREATURE_TYPE_GUILD: + case CRITERIA_TYPE_COMPLETE_ARCHAEOLOGY_PROJECTS: + case CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE_TYPE: + case CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE: + case CRITERIA_TYPE_LFR_DUNGEONS_COMPLETED: + case CRITERIA_TYPE_LFR_LEAVES: + case CRITERIA_TYPE_LFR_VOTE_KICKS_INITIATED_BY_PLAYER: + case CRITERIA_TYPE_LFR_VOTE_KICKS_NOT_INIT_BY_PLAYER: + case CRITERIA_TYPE_BE_KICKED_FROM_LFR: + case CRITERIA_TYPE_COUNT_OF_LFR_QUEUE_BOOSTS_BY_TANK: + case CRITERIA_TYPE_COMPLETE_SCENARIO_COUNT: + case CRITERIA_TYPE_COMPLETE_SCENARIO: + case CRITERIA_TYPE_CAPTURE_BATTLE_PET: + case CRITERIA_TYPE_WIN_PET_BATTLE: + case CRITERIA_TYPE_LEVEL_BATTLE_PET: + case CRITERIA_TYPE_CAPTURE_BATTLE_PET_CREDIT: + case CRITERIA_TYPE_LEVEL_BATTLE_PET_CREDIT: + case CRITERIA_TYPE_ENTER_AREA: + case CRITERIA_TYPE_LEAVE_AREA: + case CRITERIA_TYPE_COMPLETE_DUNGEON_ENCOUNTER: + case CRITERIA_TYPE_UPGRADE_GARRISON_BUILDING: + case CRITERIA_TYPE_CONSTRUCT_GARRISON_BUILDING: + case CRITERIA_TYPE_UPGRADE_GARRISON: + case CRITERIA_TYPE_START_GARRISON_MISSION: + case CRITERIA_TYPE_COMPLETE_GARRISON_MISSION_COUNT: + case CRITERIA_TYPE_COMPLETE_GARRISON_MISSION: + case CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER_COUNT: + case CRITERIA_TYPE_LEARN_GARRISON_BLUEPRINT_COUNT: + case CRITERIA_TYPE_COMPLETE_GARRISON_SHIPMENT: + case CRITERIA_TYPE_RAISE_GARRISON_FOLLOWER_ITEM_LEVEL: + case CRITERIA_TYPE_RAISE_GARRISON_FOLLOWER_LEVEL: + case CRITERIA_TYPE_OWN_TOY: + case CRITERIA_TYPE_OWN_TOY_COUNT: + case CRITERIA_TYPE_OWN_HEIRLOOMS: + break; // Not implemented yet :( + } + + for (CriteriaTree const* tree : *trees) + { + if (IsCompletedCriteriaTree(tree)) + CompletedCriteriaTree(tree, referencePlayer); + + AfterCriteriaTreeUpdate(tree, referencePlayer); + } + } +} + +void CriteriaHandler::UpdateTimedCriteria(uint32 timeDiff) +{ + if (!_timeCriteriaTrees.empty()) + { + for (auto itr = _timeCriteriaTrees.begin(); itr != _timeCriteriaTrees.end();) + { + // Time is up, remove timer and reset progress + if (itr->second <= timeDiff) + { + CriteriaTree const* criteriaTree = sCriteriaMgr->GetCriteriaTree(itr->first); + if (criteriaTree->Criteria) + RemoveCriteriaProgress(criteriaTree->Criteria); + + itr = _timeCriteriaTrees.erase(itr); + } + else + { + itr->second -= timeDiff; + ++itr; + } + } + } +} + +void CriteriaHandler::StartCriteriaTimer(CriteriaTimedTypes type, uint32 entry, uint32 timeLost /* = 0 */) +{ + CriteriaList const& criteriaList = sCriteriaMgr->GetTimedCriteriaByType(type); + for (Criteria const* criteria : criteriaList) + { + if (criteria->Entry->StartAsset != entry) + continue; + + CriteriaTreeList const* trees = sCriteriaMgr->GetCriteriaTreesByCriteria(criteria->ID); + bool canStart = false; + for (CriteriaTree const* tree : *trees) + { + if (_timeCriteriaTrees.find(tree->ID) == _timeCriteriaTrees.end() && !IsCompletedCriteriaTree(tree)) + { + // Start the timer + if (criteria->Entry->StartTimer * IN_MILLISECONDS > timeLost) + { + _timeCriteriaTrees[tree->ID] = criteria->Entry->StartTimer * IN_MILLISECONDS - timeLost; + canStart = true; + } + } + } + + if (!canStart) + continue; + + // and at client too + SetCriteriaProgress(criteria, 0, nullptr, PROGRESS_SET); + } +} + +void CriteriaHandler::RemoveCriteriaTimer(CriteriaTimedTypes type, uint32 entry) +{ + CriteriaList const& criteriaList = sCriteriaMgr->GetTimedCriteriaByType(type); + for (Criteria const* criteria : criteriaList) + { + if (criteria->Entry->StartAsset != entry) + continue; + + CriteriaTreeList const* trees = sCriteriaMgr->GetCriteriaTreesByCriteria(criteria->ID); + // Remove the timer from all trees + for (CriteriaTree const* tree : *trees) + _timeCriteriaTrees.erase(tree->ID); + + // remove progress + RemoveCriteriaProgress(criteria); + } +} + +CriteriaProgress* CriteriaHandler::GetCriteriaProgress(Criteria const* entry) +{ + auto iter = _criteriaProgress.find(entry->ID); + if (iter == _criteriaProgress.end()) + return nullptr; + + return &iter->second; +} + +void CriteriaHandler::SetCriteriaProgress(Criteria const* criteria, uint64 changeValue, Player* referencePlayer, ProgressType progressType) +{ + // Don't allow to cheat - doing timed criteria without timer active + CriteriaTreeList const* trees = nullptr; + if (criteria->Entry->StartTimer) + { + trees = sCriteriaMgr->GetCriteriaTreesByCriteria(criteria->ID); + if (!trees) + return; + + bool hasTreeForTimed = false; + for (CriteriaTree const* tree : *trees) + { + auto timedIter = _timeCriteriaTrees.find(tree->ID); + if (timedIter != _timeCriteriaTrees.end()) + { + hasTreeForTimed = true; + break; + } + } + + if (!hasTreeForTimed) + return; + } + + TC_LOG_DEBUG("criteria", "CriteriaHandler::SetCriteriaProgress(%u, " UI64FMTD ") for %s", criteria->ID, changeValue, GetOwnerInfo().c_str()); + + CriteriaProgress* progress = GetCriteriaProgress(criteria); + if (!progress) + { + // not create record for 0 counter but allow it for timed criteria + // we will need to send 0 progress to client to start the timer + if (changeValue == 0 && !criteria->Entry->StartTimer) + return; + + progress = &_criteriaProgress[criteria->ID]; + progress->Counter = changeValue; + } + else + { + uint64 newValue = 0; + switch (progressType) + { + case PROGRESS_SET: + newValue = changeValue; + break; + case PROGRESS_ACCUMULATE: + { + // avoid overflow + uint64 max_value = std::numeric_limits<uint64>::max(); + newValue = max_value - progress->Counter > changeValue ? progress->Counter + changeValue : max_value; + break; + } + case PROGRESS_HIGHEST: + newValue = progress->Counter < changeValue ? changeValue : progress->Counter; + break; + } + + // not update (not mark as changed) if counter will have same value + if (progress->Counter == newValue && !criteria->Entry->StartTimer) + return; + + progress->Counter = newValue; + } + + progress->Changed = true; + progress->Date = time(NULL); // set the date to the latest update. + progress->PlayerGUID = referencePlayer ? referencePlayer->GetGUID() : ObjectGuid::Empty; + + uint32 timeElapsed = 0; + + if (criteria->Entry->StartTimer) + { + ASSERT(trees); + + for (CriteriaTree const* tree : *trees) + { + auto timedIter = _timeCriteriaTrees.find(tree->ID); + if (timedIter != _timeCriteriaTrees.end()) + { + // Client expects this in packet + timeElapsed = criteria->Entry->StartTimer - (timedIter->second / IN_MILLISECONDS); + + // Remove the timer, we wont need it anymore + if (IsCompletedCriteriaTree(tree)) + _timeCriteriaTrees.erase(timedIter); + } + } + } + + SendCriteriaUpdate(criteria, progress, timeElapsed, true); +} + +void CriteriaHandler::RemoveCriteriaProgress(Criteria const* criteria) +{ + if (!criteria) + return; + + auto criteriaProgress = _criteriaProgress.find(criteria->ID); + if (criteriaProgress == _criteriaProgress.end()) + return; + + SendCriteriaProgressRemoved(criteria->ID); + + _criteriaProgress.erase(criteriaProgress); +} + +bool CriteriaHandler::IsCompletedCriteriaTree(CriteriaTree const* tree) +{ + if (!CanCompleteCriteriaTree(tree)) + 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 (CriteriaTree const* node : tree->Children) + { + if (IsCompletedCriteriaTree(node)) + ++completedCount; + else + hasAll = false; + + if (op & CRITERIA_TREE_OPERATOR_ANY && completedCount >= requiredCount) + { + if (!tree->Criteria) + return true; + + break; + } + } + + if (op & CRITERIA_TREE_OPERATOR_ANY && completedCount < requiredCount) + return false; + + if (op & CRITERIA_TREE_OPERATOR_ALL && !hasAll) + return false; + + if (!tree->Criteria) + return true; + + return IsCompletedCriteria(tree->Criteria, requiredCount); +} + +bool CriteriaHandler::CanCompleteCriteriaTree(CriteriaTree const* /*tree*/) +{ + return true; +} + +bool CriteriaHandler::IsCompletedCriteria(Criteria const* criteria, uint64 requiredAmount) +{ + CriteriaProgress const* progress = GetCriteriaProgress(criteria); + if (!progress) + return false; + + switch (CriteriaTypes(criteria->Entry->Type)) + { + case CRITERIA_TYPE_WIN_BG: + case CRITERIA_TYPE_KILL_CREATURE: + case CRITERIA_TYPE_REACH_LEVEL: + case CRITERIA_TYPE_REACH_GUILD_LEVEL: + case CRITERIA_TYPE_REACH_SKILL_LEVEL: + case CRITERIA_TYPE_COMPLETE_QUEST_COUNT: + case CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY: + case CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE: + case CRITERIA_TYPE_DAMAGE_DONE: + case CRITERIA_TYPE_HEALING_DONE: + case CRITERIA_TYPE_COMPLETE_DAILY_QUEST: + case CRITERIA_TYPE_FALL_WITHOUT_DYING: + case CRITERIA_TYPE_BE_SPELL_TARGET: + case CRITERIA_TYPE_BE_SPELL_TARGET2: + case CRITERIA_TYPE_CAST_SPELL: + case CRITERIA_TYPE_CAST_SPELL2: + case CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE: + case CRITERIA_TYPE_HONORABLE_KILL_AT_AREA: + case CRITERIA_TYPE_HONORABLE_KILL: + case CRITERIA_TYPE_EARN_HONORABLE_KILL: + case CRITERIA_TYPE_OWN_ITEM: + case CRITERIA_TYPE_WIN_RATED_ARENA: + case CRITERIA_TYPE_HIGHEST_PERSONAL_RATING: + case CRITERIA_TYPE_USE_ITEM: + case CRITERIA_TYPE_LOOT_ITEM: + case CRITERIA_TYPE_BUY_BANK_SLOT: + case CRITERIA_TYPE_GAIN_REPUTATION: + case CRITERIA_TYPE_GAIN_EXALTED_REPUTATION: + case CRITERIA_TYPE_VISIT_BARBER_SHOP: + case CRITERIA_TYPE_EQUIP_EPIC_ITEM: + case CRITERIA_TYPE_ROLL_NEED_ON_LOOT: + case CRITERIA_TYPE_ROLL_GREED_ON_LOOT: + case CRITERIA_TYPE_HK_CLASS: + case CRITERIA_TYPE_HK_RACE: + case CRITERIA_TYPE_DO_EMOTE: + case CRITERIA_TYPE_EQUIP_ITEM: + case CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD: + case CRITERIA_TYPE_LOOT_MONEY: + case CRITERIA_TYPE_USE_GAMEOBJECT: + case CRITERIA_TYPE_SPECIAL_PVP_KILL: + case CRITERIA_TYPE_FISH_IN_GAMEOBJECT: + case CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS: + case CRITERIA_TYPE_WIN_DUEL: + case CRITERIA_TYPE_LOOT_TYPE: + case CRITERIA_TYPE_LEARN_SKILL_LINE: + case CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS: + case CRITERIA_TYPE_GET_KILLING_BLOWS: + case CRITERIA_TYPE_CURRENCY: + case CRITERIA_TYPE_PLACE_GARRISON_BUILDING: + case CRITERIA_TYPE_OWN_BATTLE_PET_COUNT: + return progress->Counter >= requiredAmount; + case CRITERIA_TYPE_COMPLETE_ACHIEVEMENT: + case CRITERIA_TYPE_COMPLETE_QUEST: + case CRITERIA_TYPE_LEARN_SPELL: + case CRITERIA_TYPE_EXPLORE_AREA: + case CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER: + case CRITERIA_TYPE_OWN_BATTLE_PET: + return progress->Counter >= 1; + case CRITERIA_TYPE_LEARN_SKILL_LEVEL: + return progress->Counter >= (requiredAmount * 75); + case CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS: + return progress->Counter >= 9000; + case CRITERIA_TYPE_WIN_ARENA: + return requiredAmount && progress->Counter >= requiredAmount; + case CRITERIA_TYPE_ON_LOGIN: + return true; + // handle all statistic-only criteria here + case CRITERIA_TYPE_COMPLETE_BATTLEGROUND: + case CRITERIA_TYPE_DEATH_AT_MAP: + case CRITERIA_TYPE_DEATH: + case CRITERIA_TYPE_DEATH_IN_DUNGEON: + case CRITERIA_TYPE_KILLED_BY_CREATURE: + case CRITERIA_TYPE_KILLED_BY_PLAYER: + case CRITERIA_TYPE_DEATHS_FROM: + case CRITERIA_TYPE_HIGHEST_TEAM_RATING: + case CRITERIA_TYPE_MONEY_FROM_VENDORS: + case CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS: + case CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS: + case CRITERIA_TYPE_GOLD_SPENT_AT_BARBER: + case CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL: + case CRITERIA_TYPE_LOSE_DUEL: + case CRITERIA_TYPE_KILL_CREATURE_TYPE: + case CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS: + case CRITERIA_TYPE_CREATE_AUCTION: + case CRITERIA_TYPE_HIGHEST_AUCTION_BID: + case CRITERIA_TYPE_HIGHEST_AUCTION_SOLD: + case CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED: + case CRITERIA_TYPE_WON_AUCTIONS: + case CRITERIA_TYPE_GAIN_REVERED_REPUTATION: + case CRITERIA_TYPE_GAIN_HONORED_REPUTATION: + case CRITERIA_TYPE_KNOWN_FACTIONS: + case CRITERIA_TYPE_LOOT_EPIC_ITEM: + case CRITERIA_TYPE_RECEIVE_EPIC_ITEM: + case CRITERIA_TYPE_ROLL_NEED: + case CRITERIA_TYPE_ROLL_GREED: + case CRITERIA_TYPE_QUEST_ABANDONED: + case CRITERIA_TYPE_FLIGHT_PATHS_TAKEN: + case CRITERIA_TYPE_ACCEPTED_SUMMONINGS: + default: + break; + } + + return false; +} + +bool CriteriaHandler::CanUpdateCriteria(Criteria const* criteria, CriteriaTreeList const* trees, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit const* unit, Player* referencePlayer) +{ + if (DisableMgr::IsDisabledFor(DISABLE_TYPE_CRITERIA, criteria->ID, nullptr)) + { + TC_LOG_TRACE("criteria", "CriteriaHandler::CanUpdateCriteria: (Id: %u Type %s) Disabled", criteria->ID, CriteriaMgr::GetCriteriaTypeString(criteria->Entry->Type)); + return false; + } + + bool treeRequirementPassed = false; + for (CriteriaTree const* tree : *trees) + { + if (!CanUpdateCriteriaTree(criteria, tree, referencePlayer)) + continue; + + treeRequirementPassed = true; + break; + } + + if (!treeRequirementPassed) + return false; + + if (!RequirementsSatisfied(criteria, miscValue1, miscValue2, miscValue3, unit, referencePlayer)) + { + TC_LOG_TRACE("criteria", "CriteriaHandler::CanUpdateCriteria: (Id: %u Type %s) Requirements not satisfied", criteria->ID, CriteriaMgr::GetCriteriaTypeString(criteria->Entry->Type)); + return false; + } + + if (criteria->Modifier && !AdditionalRequirementsSatisfied(criteria->Modifier, miscValue1, miscValue2, unit, referencePlayer)) + { + TC_LOG_TRACE("criteria", "CriteriaHandler::CanUpdateCriteria: (Id: %u Type %s) Requirements have not been satisfied", criteria->ID, CriteriaMgr::GetCriteriaTypeString(criteria->Entry->Type)); + return false; + } + + if (!ConditionsSatisfied(criteria, referencePlayer)) + { + TC_LOG_TRACE("criteria", "CriteriaHandler::CanUpdateCriteria: (Id: %u Type %s) Conditions have not been satisfied", criteria->ID, CriteriaMgr::GetCriteriaTypeString(criteria->Entry->Type)); + return false; + } + + return true; +} + +bool CriteriaHandler::ConditionsSatisfied(Criteria const* criteria, Player* referencePlayer) const +{ + if (!criteria->Entry->FailEvent) + return true; + + switch (criteria->Entry->FailEvent) + { + case CRITERIA_CONDITION_BG_MAP: + if (!referencePlayer->InBattleground()) + return false; + break; + case CRITERIA_CONDITION_NOT_IN_GROUP: + if (referencePlayer->GetGroup()) + return false; + break; + default: + break; + } + + return true; +} + +bool CriteriaHandler::RequirementsSatisfied(Criteria const* criteria, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit const* unit, Player* referencePlayer) const +{ + switch (CriteriaTypes(criteria->Entry->Type)) + { + case CRITERIA_TYPE_ACCEPTED_SUMMONINGS: + case CRITERIA_TYPE_COMPLETE_DAILY_QUEST: + case CRITERIA_TYPE_CREATE_AUCTION: + case CRITERIA_TYPE_FALL_WITHOUT_DYING: + case CRITERIA_TYPE_FLIGHT_PATHS_TAKEN: + case CRITERIA_TYPE_GET_KILLING_BLOWS: + case CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS: + case CRITERIA_TYPE_GOLD_SPENT_AT_BARBER: + case CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL: + case CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS: + case CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING: + case CRITERIA_TYPE_HIGHEST_AUCTION_BID: + case CRITERIA_TYPE_HIGHEST_AUCTION_SOLD: + case CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED: + case CRITERIA_TYPE_HIGHEST_HEAL_CAST: + case CRITERIA_TYPE_HIGHEST_HIT_DEALT: + case CRITERIA_TYPE_HIGHEST_HIT_RECEIVED: + case CRITERIA_TYPE_HONORABLE_KILL: + case CRITERIA_TYPE_LOOT_MONEY: + case CRITERIA_TYPE_LOSE_DUEL: + case CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD: + case CRITERIA_TYPE_MONEY_FROM_VENDORS: + case CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS: + case CRITERIA_TYPE_QUEST_ABANDONED: + case CRITERIA_TYPE_REACH_GUILD_LEVEL: + case CRITERIA_TYPE_ROLL_GREED: + case CRITERIA_TYPE_ROLL_NEED: + case CRITERIA_TYPE_SPECIAL_PVP_KILL: + case CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED: + case CRITERIA_TYPE_TOTAL_HEALING_RECEIVED: + case CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS: + case CRITERIA_TYPE_VISIT_BARBER_SHOP: + case CRITERIA_TYPE_WIN_DUEL: + case CRITERIA_TYPE_WIN_RATED_ARENA: + case CRITERIA_TYPE_WON_AUCTIONS: + if (!miscValue1) + return false; + break; + case CRITERIA_TYPE_BUY_BANK_SLOT: + case CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY: + case CRITERIA_TYPE_COMPLETE_QUEST_COUNT: + case CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS: + case CRITERIA_TYPE_GAIN_EXALTED_REPUTATION: + case CRITERIA_TYPE_GAIN_HONORED_REPUTATION: + case CRITERIA_TYPE_GAIN_REVERED_REPUTATION: + case CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED: + case CRITERIA_TYPE_HIGHEST_PERSONAL_RATING: + case CRITERIA_TYPE_KNOWN_FACTIONS: + case CRITERIA_TYPE_REACH_LEVEL: + case CRITERIA_TYPE_ON_LOGIN: + break; + case CRITERIA_TYPE_COMPLETE_ACHIEVEMENT: + if (!RequiredAchievementSatisfied(criteria->Entry->Asset.AchievementID)) + return false; + break; + case CRITERIA_TYPE_WIN_BG: + if (!miscValue1 || criteria->Entry->Asset.MapID != referencePlayer->GetMapId()) + return false; + break; + case CRITERIA_TYPE_KILL_CREATURE: + if (!miscValue1 || criteria->Entry->Asset.CreatureID != miscValue1) + return false; + break; + case CRITERIA_TYPE_REACH_SKILL_LEVEL: + case CRITERIA_TYPE_LEARN_SKILL_LEVEL: + // update at loading or specific skill update + if (miscValue1 && miscValue1 != criteria->Entry->Asset.SkillID) + return false; + break; + case CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE: + if (miscValue1 && miscValue1 != criteria->Entry->Asset.ZoneID) + return false; + break; + case CRITERIA_TYPE_COMPLETE_BATTLEGROUND: + case CRITERIA_TYPE_DEATH_AT_MAP: + if (!miscValue1 || referencePlayer->GetMapId() != criteria->Entry->Asset.MapID) + return false; + break; + case CRITERIA_TYPE_DEATH: + { + if (!miscValue1) + return false; + break; + } + case CRITERIA_TYPE_DEATH_IN_DUNGEON: + { + if (!miscValue1) + return false; + + Map const* map = referencePlayer->IsInWorld() ? referencePlayer->GetMap() : sMapMgr->FindMap(referencePlayer->GetMapId(), referencePlayer->GetInstanceId()); + if (!map || !map->IsDungeon()) + return false; + + //FIXME: work only for instances where max == min for players + if (map->ToInstanceMap()->GetMaxPlayers() != criteria->Entry->Asset.GroupSize) + return false; + break; + } + case CRITERIA_TYPE_KILLED_BY_CREATURE: + if (!miscValue1 || miscValue1 != criteria->Entry->Asset.CreatureID) + return false; + break; + case CRITERIA_TYPE_KILLED_BY_PLAYER: + if (!miscValue1 || !unit || unit->GetTypeId() != TYPEID_PLAYER) + return false; + break; + case CRITERIA_TYPE_DEATHS_FROM: + if (!miscValue1 || miscValue2 != criteria->Entry->Asset.DamageType) + return false; + break; + case CRITERIA_TYPE_COMPLETE_QUEST: + { + // if miscValues != 0, it contains the questID. + if (miscValue1) + { + if (miscValue1 != criteria->Entry->Asset.QuestID) + return false; + } + else + { + // login case. + if (!referencePlayer->GetQuestRewardStatus(criteria->Entry->Asset.QuestID)) + return false; + } + + if (CriteriaDataSet const* data = sCriteriaMgr->GetCriteriaDataSet(criteria)) + if (!data->Meets(referencePlayer, unit)) + return false; + break; + } + case CRITERIA_TYPE_BE_SPELL_TARGET: + case CRITERIA_TYPE_BE_SPELL_TARGET2: + case CRITERIA_TYPE_CAST_SPELL: + case CRITERIA_TYPE_CAST_SPELL2: + if (!miscValue1 || miscValue1 != criteria->Entry->Asset.SpellID) + return false; + break; + case CRITERIA_TYPE_LEARN_SPELL: + if (miscValue1 && miscValue1 != criteria->Entry->Asset.SpellID) + return false; + + if (!referencePlayer->HasSpell(criteria->Entry->Asset.SpellID)) + return false; + break; + case 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 != criteria->Entry->Asset.LootType) + return false; + break; + case CRITERIA_TYPE_OWN_ITEM: + if (miscValue1 && criteria->Entry->Asset.ItemID != miscValue1) + return false; + break; + case CRITERIA_TYPE_USE_ITEM: + case CRITERIA_TYPE_LOOT_ITEM: + case CRITERIA_TYPE_EQUIP_ITEM: + if (!miscValue1 || criteria->Entry->Asset.ItemID != miscValue1) + return false; + break; + case CRITERIA_TYPE_EXPLORE_AREA: + { + WorldMapOverlayEntry const* worldOverlayEntry = sWorldMapOverlayStore.LookupEntry(criteria->Entry->Asset.WorldMapOverlayID); + if (!worldOverlayEntry) + break; + + bool matchFound = false; + for (int j = 0; j < MAX_WORLD_MAP_OVERLAY_AREA_IDX; ++j) + { + AreaTableEntry const* area = sAreaTableStore.LookupEntry(worldOverlayEntry->AreaID[j]); + if (!area) + break; + + if (area->AreaBit < 0) + continue; + + uint16 playerIndexOffset = uint16(uint32(area->AreaBit) / 32); + if (playerIndexOffset >= PLAYER_EXPLORED_ZONES_SIZE) + continue; + + uint32 mask = 1 << (uint32(area->AreaBit) % 32); + if (referencePlayer->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + playerIndexOffset) & mask) + { + matchFound = true; + break; + } + } + + if (!matchFound) + return false; + break; + } + case CRITERIA_TYPE_GAIN_REPUTATION: + if (miscValue1 && miscValue1 != criteria->Entry->Asset.FactionID) + return false; + break; + case CRITERIA_TYPE_EQUIP_EPIC_ITEM: + // miscValue1 = itemid miscValue2 = itemSlot + if (!miscValue1 || miscValue2 != criteria->Entry->Asset.ItemSlot) + return false; + break; + case CRITERIA_TYPE_ROLL_NEED_ON_LOOT: + case CRITERIA_TYPE_ROLL_GREED_ON_LOOT: + { + // miscValue1 = itemid miscValue2 = diced value + if (!miscValue1 || miscValue2 != criteria->Entry->Asset.RollValue) + return false; + + ItemTemplate const* proto = sObjectMgr->GetItemTemplate(uint32(miscValue1)); + if (!proto) + return false; + break; + } + case CRITERIA_TYPE_DO_EMOTE: + if (!miscValue1 || miscValue1 != criteria->Entry->Asset.EmoteID) + return false; + break; + case CRITERIA_TYPE_DAMAGE_DONE: + case CRITERIA_TYPE_HEALING_DONE: + if (!miscValue1) + return false; + + if (criteria->Entry->FailEvent == CRITERIA_CONDITION_BG_MAP) + { + if (!referencePlayer->InBattleground()) + return false; + + // map specific case (BG in fact) expected player targeted damage/heal + if (!unit || unit->GetTypeId() != TYPEID_PLAYER) + return false; + } + break; + case CRITERIA_TYPE_USE_GAMEOBJECT: + case CRITERIA_TYPE_FISH_IN_GAMEOBJECT: + if (!miscValue1 || miscValue1 != criteria->Entry->Asset.GameObjectID) + return false; + break; + case CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS: + case CRITERIA_TYPE_LEARN_SKILL_LINE: + if (miscValue1 && miscValue1 != criteria->Entry->Asset.SkillID) + return false; + break; + case CRITERIA_TYPE_LOOT_EPIC_ITEM: + case CRITERIA_TYPE_RECEIVE_EPIC_ITEM: + { + if (!miscValue1) + return false; + ItemTemplate const* proto = sObjectMgr->GetItemTemplate(uint32(miscValue1)); + if (!proto || proto->GetQuality() < ITEM_QUALITY_EPIC) + return false; + break; + } + case CRITERIA_TYPE_HK_CLASS: + if (!miscValue1 || miscValue1 != criteria->Entry->Asset.ClassID) + return false; + break; + case CRITERIA_TYPE_HK_RACE: + if (!miscValue1 || miscValue1 != criteria->Entry->Asset.RaceID) + return false; + break; + case CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE: + if (!miscValue1 || miscValue1 != criteria->Entry->Asset.ObjectiveId) + return false; + break; + case CRITERIA_TYPE_HONORABLE_KILL_AT_AREA: + if (!miscValue1 || miscValue1 != criteria->Entry->Asset.AreaID) + return false; + break; + case CRITERIA_TYPE_CURRENCY: + if (!miscValue1 || !miscValue2 || int64(miscValue2) < 0 + || miscValue1 != criteria->Entry->Asset.CurrencyID) + return false; + break; + case CRITERIA_TYPE_WIN_ARENA: + if (miscValue1 != criteria->Entry->Asset.MapID) + return false; + break; + case CRITERIA_TYPE_HIGHEST_TEAM_RATING: + return false; + case CRITERIA_TYPE_PLACE_GARRISON_BUILDING: + if (miscValue1 != criteria->Entry->Asset.GarrBuildingID) + return false; + break; + default: + break; + } + return true; +} + +bool CriteriaHandler::AdditionalRequirementsSatisfied(ModifierTreeNode const* tree, uint64 miscValue1, uint64 miscValue2, Unit const* unit, Player* referencePlayer) const +{ + 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 (CriteriaAdditionalCondition(reqType)) + { + case CRITERIA_ADDITIONAL_CONDITION_TARGET_CREATURE_ENTRY: // 4 + if (!unit || unit->GetEntry() != reqValue) + return false; + break; + case CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_PLAYER: // 5 + if (!unit || unit->GetTypeId() != TYPEID_PLAYER) + return false; + break; + case CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_DEAD: // 6 + if (!unit || unit->IsAlive()) + return false; + break; + case CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_ENEMY: // 7 + if (!unit || !referencePlayer->IsHostileTo(unit)) + return false; + break; + case CRITERIA_ADDITIONAL_CONDITION_SOURCE_HAS_AURA: // 8 + if (!referencePlayer->HasAura(reqValue)) + return false; + break; + case CRITERIA_ADDITIONAL_CONDITION_TARGET_HAS_AURA: // 10 + if (!unit || !unit->HasAura(reqValue)) + return false; + case CRITERIA_ADDITIONAL_CONDITION_TARGET_HAS_AURA_TYPE: // 11 + if (!unit || !unit->HasAuraType(AuraType(reqValue))) + return false; + break; + case 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 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 CRITERIA_ADDITIONAL_CONDITION_SOURCE_AREA_OR_ZONE: // 17 + { + uint32 zoneId, areaId; + referencePlayer->GetZoneAndAreaId(zoneId, areaId); + if (zoneId != reqValue && areaId != reqValue) + return false; + break; + } + case 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 CRITERIA_ADDITIONAL_CONDITION_MAP_DIFFICULTY: // 20 + if (uint32(referencePlayer->GetMap()->GetDifficultyID()) != reqValue) + return false; + break; + case CRITERIA_ADDITIONAL_CONDITION_ARENA_TYPE: + { + Battleground* bg = referencePlayer->GetBattleground(); + if (!bg || !bg->isArena() || bg->GetArenaType() != reqValue) + return false; + break; + } + case CRITERIA_ADDITIONAL_CONDITION_SOURCE_RACE: // 25 + if (referencePlayer->getRace() != reqValue) + return false; + break; + case CRITERIA_ADDITIONAL_CONDITION_SOURCE_CLASS: // 26 + if (referencePlayer->getClass() != reqValue) + return false; + break; + case CRITERIA_ADDITIONAL_CONDITION_TARGET_RACE: // 27 + if (!unit || unit->GetTypeId() != TYPEID_PLAYER || unit->getRace() != reqValue) + return false; + break; + case CRITERIA_ADDITIONAL_CONDITION_TARGET_CLASS: // 28 + if (!unit || unit->GetTypeId() != TYPEID_PLAYER || unit->getClass() != reqValue) + return false; + break; + case CRITERIA_ADDITIONAL_CONDITION_MAX_GROUP_MEMBERS: // 29 + if (referencePlayer->GetGroup() && referencePlayer->GetGroup()->GetMembersCount() >= reqValue) + return false; + break; + case 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 CRITERIA_ADDITIONAL_CONDITION_SOURCE_MAP: // 32 + if (referencePlayer->GetMapId() != reqValue) + return false; + break; + case CRITERIA_ADDITIONAL_CONDITION_TITLE_BIT_INDEX: // 38 + // miscValue1 is title's bit index + if (miscValue1 != reqValue) + return false; + break; + case CRITERIA_ADDITIONAL_CONDITION_SOURCE_LEVEL: // 39 + if (referencePlayer->getLevel() != reqValue) + return false; + break; + case CRITERIA_ADDITIONAL_CONDITION_TARGET_LEVEL: // 40 + if (!unit || unit->getLevel() != reqValue) + return false; + break; + case CRITERIA_ADDITIONAL_CONDITION_TARGET_ZONE: // 41 + if (!unit || unit->GetZoneId() != reqValue) + return false; + break; + case CRITERIA_ADDITIONAL_CONDITION_TARGET_HEALTH_PERCENT_BELOW: // 46 + if (!unit || unit->GetHealthPct() >= reqValue) + return false; + break; + case CRITERIA_ADDITIONAL_CONDITION_BATTLE_PET_SPECIES: // 91 + if (miscValue1 != reqValue) + return false; + break; + case CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_QUALITY: // 145 + { + if (!referencePlayer) + return false; + Garrison* garrison = referencePlayer->GetGarrison(); + if (!garrison) + return false; + Garrison::Follower const* follower = garrison->GetFollower(miscValue1); + if (!follower || follower->PacketInfo.Quality != reqValue) + return false; + + break; + } + case CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_LEVEL: // 146 + { + if (!referencePlayer) + return false; + Garrison* garrison = referencePlayer->GetGarrison(); + if (!garrison) + return false; + Garrison::Follower const* follower = garrison->GetFollower(miscValue1); + if (!follower || follower->PacketInfo.FollowerLevel < reqValue) + return false; + + break; + } + case CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_ILVL: // 184 + { + if (!referencePlayer) + return false; + Garrison* garrison = referencePlayer->GetGarrison(); + if (!garrison) + return false; + Garrison::Follower const* follower = garrison->GetFollower(miscValue1); + if (!follower || follower->GetItemLevel() < reqValue) + return false; + break; + } + default: + break; + } + return true; +} + +char const* CriteriaMgr::GetCriteriaTypeString(uint32 type) +{ + return GetCriteriaTypeString(CriteriaTypes(type)); +} + +char const* CriteriaMgr::GetCriteriaTypeString(CriteriaTypes type) +{ + switch (type) + { + case CRITERIA_TYPE_KILL_CREATURE: + return "KILL_CREATURE"; + case CRITERIA_TYPE_WIN_BG: + return "TYPE_WIN_BG"; + case CRITERIA_TYPE_COMPLETE_ARCHAEOLOGY_PROJECTS: + return "COMPLETE_RESEARCH"; + case CRITERIA_TYPE_REACH_LEVEL: + return "REACH_LEVEL"; + case CRITERIA_TYPE_REACH_SKILL_LEVEL: + return "REACH_SKILL_LEVEL"; + case CRITERIA_TYPE_COMPLETE_ACHIEVEMENT: + return "COMPLETE_ACHIEVEMENT"; + case CRITERIA_TYPE_COMPLETE_QUEST_COUNT: + return "COMPLETE_QUEST_COUNT"; + case CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY: + return "COMPLETE_DAILY_QUEST_DAILY"; + case CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE: + return "COMPLETE_QUESTS_IN_ZONE"; + case CRITERIA_TYPE_CURRENCY: + return "CURRENCY"; + case CRITERIA_TYPE_DAMAGE_DONE: + return "DAMAGE_DONE"; + case CRITERIA_TYPE_COMPLETE_DAILY_QUEST: + return "COMPLETE_DAILY_QUEST"; + case CRITERIA_TYPE_COMPLETE_BATTLEGROUND: + return "COMPLETE_BATTLEGROUND"; + case CRITERIA_TYPE_DEATH_AT_MAP: + return "DEATH_AT_MAP"; + case CRITERIA_TYPE_DEATH: + return "DEATH"; + case CRITERIA_TYPE_DEATH_IN_DUNGEON: + return "DEATH_IN_DUNGEON"; + case CRITERIA_TYPE_COMPLETE_RAID: + return "COMPLETE_RAID"; + case CRITERIA_TYPE_KILLED_BY_CREATURE: + return "KILLED_BY_CREATURE"; + case CRITERIA_TYPE_KILLED_BY_PLAYER: + return "KILLED_BY_PLAYER"; + case CRITERIA_TYPE_FALL_WITHOUT_DYING: + return "FALL_WITHOUT_DYING"; + case CRITERIA_TYPE_DEATHS_FROM: + return "DEATHS_FROM"; + case CRITERIA_TYPE_COMPLETE_QUEST: + return "COMPLETE_QUEST"; + case CRITERIA_TYPE_BE_SPELL_TARGET: + return "BE_SPELL_TARGET"; + case CRITERIA_TYPE_CAST_SPELL: + return "CAST_SPELL"; + case CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE: + return "BG_OBJECTIVE_CAPTURE"; + case CRITERIA_TYPE_HONORABLE_KILL_AT_AREA: + return "HONORABLE_KILL_AT_AREA"; + case CRITERIA_TYPE_WIN_ARENA: + return "WIN_ARENA"; + case CRITERIA_TYPE_PLAY_ARENA: + return "PLAY_ARENA"; + case CRITERIA_TYPE_LEARN_SPELL: + return "LEARN_SPELL"; + case CRITERIA_TYPE_HONORABLE_KILL: + return "HONORABLE_KILL"; + case CRITERIA_TYPE_OWN_ITEM: + return "OWN_ITEM"; + case CRITERIA_TYPE_WIN_RATED_ARENA: + return "WIN_RATED_ARENA"; + case CRITERIA_TYPE_HIGHEST_TEAM_RATING: + return "HIGHEST_TEAM_RATING"; + case CRITERIA_TYPE_HIGHEST_PERSONAL_RATING: + return "HIGHEST_PERSONAL_RATING"; + case CRITERIA_TYPE_LEARN_SKILL_LEVEL: + return "LEARN_SKILL_LEVEL"; + case CRITERIA_TYPE_USE_ITEM: + return "USE_ITEM"; + case CRITERIA_TYPE_LOOT_ITEM: + return "LOOT_ITEM"; + case CRITERIA_TYPE_EXPLORE_AREA: + return "EXPLORE_AREA"; + case CRITERIA_TYPE_OWN_RANK: + return "OWN_RANK"; + case CRITERIA_TYPE_BUY_BANK_SLOT: + return "BUY_BANK_SLOT"; + case CRITERIA_TYPE_GAIN_REPUTATION: + return "GAIN_REPUTATION"; + case CRITERIA_TYPE_GAIN_EXALTED_REPUTATION: + return "GAIN_EXALTED_REPUTATION"; + case CRITERIA_TYPE_VISIT_BARBER_SHOP: + return "VISIT_BARBER_SHOP"; + case CRITERIA_TYPE_EQUIP_EPIC_ITEM: + return "EQUIP_EPIC_ITEM"; + case CRITERIA_TYPE_ROLL_NEED_ON_LOOT: + return "ROLL_NEED_ON_LOOT"; + case CRITERIA_TYPE_ROLL_GREED_ON_LOOT: + return "GREED_ON_LOOT"; + case CRITERIA_TYPE_HK_CLASS: + return "HK_CLASS"; + case CRITERIA_TYPE_HK_RACE: + return "HK_RACE"; + case CRITERIA_TYPE_DO_EMOTE: + return "DO_EMOTE"; + case CRITERIA_TYPE_HEALING_DONE: + return "HEALING_DONE"; + case CRITERIA_TYPE_GET_KILLING_BLOWS: + return "GET_KILLING_BLOWS"; + case CRITERIA_TYPE_EQUIP_ITEM: + return "EQUIP_ITEM"; + case CRITERIA_TYPE_MONEY_FROM_VENDORS: + return "MONEY_FROM_VENDORS"; + case CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS: + return "GOLD_SPENT_FOR_TALENTS"; + case CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS: + return "NUMBER_OF_TALENT_RESETS"; + case CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD: + return "MONEY_FROM_QUEST_REWARD"; + case CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING: + return "GOLD_SPENT_FOR_TRAVELLING"; + case CRITERIA_TYPE_GOLD_SPENT_AT_BARBER: + return "GOLD_SPENT_AT_BARBER"; + case CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL: + return "GOLD_SPENT_FOR_MAIL"; + case CRITERIA_TYPE_LOOT_MONEY: + return "LOOT_MONEY"; + case CRITERIA_TYPE_USE_GAMEOBJECT: + return "USE_GAMEOBJECT"; + case CRITERIA_TYPE_BE_SPELL_TARGET2: + return "BE_SPELL_TARGET2"; + case CRITERIA_TYPE_SPECIAL_PVP_KILL: + return "SPECIAL_PVP_KILL"; + case CRITERIA_TYPE_FISH_IN_GAMEOBJECT: + return "FISH_IN_GAMEOBJECT"; + case CRITERIA_TYPE_ON_LOGIN: + return "ON_LOGIN"; + case CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS: + return "LEARN_SKILLLINE_SPELLS"; + case CRITERIA_TYPE_WIN_DUEL: + return "WIN_DUEL"; + case CRITERIA_TYPE_LOSE_DUEL: + return "LOSE_DUEL"; + case CRITERIA_TYPE_KILL_CREATURE_TYPE: + return "KILL_CREATURE_TYPE"; + case CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS: + return "GOLD_EARNED_BY_AUCTIONS"; + case CRITERIA_TYPE_CREATE_AUCTION: + return "CREATE_AUCTION"; + case CRITERIA_TYPE_HIGHEST_AUCTION_BID: + return "HIGHEST_AUCTION_BID"; + case CRITERIA_TYPE_WON_AUCTIONS: + return "WON_AUCTIONS"; + case CRITERIA_TYPE_HIGHEST_AUCTION_SOLD: + return "HIGHEST_AUCTION_SOLD"; + case CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED: + return "HIGHEST_GOLD_VALUE_OWNED"; + case CRITERIA_TYPE_GAIN_REVERED_REPUTATION: + return "GAIN_REVERED_REPUTATION"; + case CRITERIA_TYPE_GAIN_HONORED_REPUTATION: + return "GAIN_HONORED_REPUTATION"; + case CRITERIA_TYPE_KNOWN_FACTIONS: + return "KNOWN_FACTIONS"; + case CRITERIA_TYPE_LOOT_EPIC_ITEM: + return "LOOT_EPIC_ITEM"; + case CRITERIA_TYPE_RECEIVE_EPIC_ITEM: + return "RECEIVE_EPIC_ITEM"; + case CRITERIA_TYPE_ROLL_NEED: + return "ROLL_NEED"; + case CRITERIA_TYPE_ROLL_GREED: + return "ROLL_GREED"; + case CRITERIA_TYPE_HIGHEST_HIT_DEALT: + return "HIT_DEALT"; + case CRITERIA_TYPE_HIGHEST_HIT_RECEIVED: + return "HIT_RECEIVED"; + case CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED: + return "TOTAL_DAMAGE_RECEIVED"; + case CRITERIA_TYPE_HIGHEST_HEAL_CAST: + return "HIGHEST_HEAL_CAST"; + case CRITERIA_TYPE_TOTAL_HEALING_RECEIVED: + return "TOTAL_HEALING_RECEIVED"; + case CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED: + return "HIGHEST_HEALING_RECEIVED"; + case CRITERIA_TYPE_QUEST_ABANDONED: + return "QUEST_ABANDONED"; + case CRITERIA_TYPE_FLIGHT_PATHS_TAKEN: + return "FLIGHT_PATHS_TAKEN"; + case CRITERIA_TYPE_LOOT_TYPE: + return "LOOT_TYPE"; + case CRITERIA_TYPE_CAST_SPELL2: + return "CAST_SPELL2"; + case CRITERIA_TYPE_LEARN_SKILL_LINE: + return "LEARN_SKILL_LINE"; + case CRITERIA_TYPE_EARN_HONORABLE_KILL: + return "EARN_HONORABLE_KILL"; + case CRITERIA_TYPE_ACCEPTED_SUMMONINGS: + return "ACCEPTED_SUMMONINGS"; + case CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS: + return "EARN_ACHIEVEMENT_POINTS"; + case CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS: + return "USE_LFD_TO_GROUP_WITH_PLAYERS"; + case CRITERIA_TYPE_SPENT_GOLD_GUILD_REPAIRS: + return "SPENT_GOLD_GUILD_REPAIRS"; + case CRITERIA_TYPE_REACH_GUILD_LEVEL: + return "REACH_GUILD_LEVEL"; + case CRITERIA_TYPE_CRAFT_ITEMS_GUILD: + return "CRAFT_ITEMS_GUILD"; + case CRITERIA_TYPE_CATCH_FROM_POOL: + return "CATCH_FROM_POOL"; + case CRITERIA_TYPE_BUY_GUILD_BANK_SLOTS: + return "BUY_GUILD_BANK_SLOTS"; + case CRITERIA_TYPE_EARN_GUILD_ACHIEVEMENT_POINTS: + return "EARN_GUILD_ACHIEVEMENT_POINTS"; + case CRITERIA_TYPE_WIN_RATED_BATTLEGROUND: + return "WIN_RATED_BATTLEGROUND"; + case CRITERIA_TYPE_REACH_BG_RATING: + return "REACH_BG_RATING"; + case CRITERIA_TYPE_BUY_GUILD_TABARD: + return "BUY_GUILD_TABARD"; + case CRITERIA_TYPE_COMPLETE_QUESTS_GUILD: + return "COMPLETE_QUESTS_GUILD"; + case CRITERIA_TYPE_HONORABLE_KILLS_GUILD: + return "HONORABLE_KILLS_GUILD"; + case CRITERIA_TYPE_KILL_CREATURE_TYPE_GUILD: + return "KILL_CREATURE_TYPE_GUILD"; + case CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE_TYPE: + return "GUILD_CHALLENGE_TYPE"; + case CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE: + return "GUILD_CHALLENGE"; + case CRITERIA_TYPE_LFR_DUNGEONS_COMPLETED: + return "LFR_DUNGEONS_COMPLETED"; + case CRITERIA_TYPE_LFR_LEAVES: + return "LFR_LEAVES"; + case CRITERIA_TYPE_LFR_VOTE_KICKS_INITIATED_BY_PLAYER: + return "LFR_VOTE_KICKS_INITIATED_BY_PLAYER"; + case CRITERIA_TYPE_LFR_VOTE_KICKS_NOT_INIT_BY_PLAYER: + return "LFR_VOTE_KICKS_NOT_INIT_BY_PLAYER"; + case CRITERIA_TYPE_BE_KICKED_FROM_LFR: + return "BE_KICKED_FROM_LFR"; + case CRITERIA_TYPE_COUNT_OF_LFR_QUEUE_BOOSTS_BY_TANK: + return "COUNT_OF_LFR_QUEUE_BOOSTS_BY_TANK"; + case CRITERIA_TYPE_COMPLETE_SCENARIO_COUNT: + return "COMPLETE_SCENARIO_COUNT"; + case CRITERIA_TYPE_COMPLETE_SCENARIO: + return "COMPLETE_SCENARIO"; + case CRITERIA_TYPE_OWN_BATTLE_PET: + return "OWN_BATTLE_PET"; + case CRITERIA_TYPE_OWN_BATTLE_PET_COUNT: + return "OWN_BATTLE_PET_COUNT"; + case CRITERIA_TYPE_CAPTURE_BATTLE_PET: + return "CAPTURE_BATTLE_PET"; + case CRITERIA_TYPE_WIN_PET_BATTLE: + return "WIN_PET_BATTLE"; + case CRITERIA_TYPE_LEVEL_BATTLE_PET: + return "LEVEL_BATTLE_PET"; + case CRITERIA_TYPE_CAPTURE_BATTLE_PET_CREDIT: + return "CAPTURE_BATTLE_PET_CREDIT"; + case CRITERIA_TYPE_LEVEL_BATTLE_PET_CREDIT: + return "LEVEL_BATTLE_PET_CREDIT"; + case CRITERIA_TYPE_ENTER_AREA: + return "ENTER_AREA"; + case CRITERIA_TYPE_LEAVE_AREA: + return "LEAVE_AREA"; + case CRITERIA_TYPE_COMPLETE_DUNGEON_ENCOUNTER: + return "COMPLETE_DUNGEON_ENCOUNTER"; + case CRITERIA_TYPE_PLACE_GARRISON_BUILDING: + return "PLACE_GARRISON_BUILDING"; + case CRITERIA_TYPE_UPGRADE_GARRISON_BUILDING: + return "UPGRADE_GARRISON_BUILDING"; + case CRITERIA_TYPE_CONSTRUCT_GARRISON_BUILDING: + return "CONSTRUCT_GARRISON_BUILDING"; + case CRITERIA_TYPE_UPGRADE_GARRISON: + return "UPGRADE_GARRISON"; + case CRITERIA_TYPE_START_GARRISON_MISSION: + return "START_GARRISON_MISSION"; + case CRITERIA_TYPE_COMPLETE_GARRISON_MISSION_COUNT: + return "COMPLETE_GARRISON_MISSION_COUNT"; + case CRITERIA_TYPE_COMPLETE_GARRISON_MISSION: + return "COMPLETE_GARRISON_MISSION"; + case CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER_COUNT: + return "RECRUIT_GARRISON_FOLLOWER_COUNT"; + case CRITERIA_TYPE_LEARN_GARRISON_BLUEPRINT_COUNT: + return "LEARN_GARRISON_BLUEPRINT_COUNT"; + case CRITERIA_TYPE_COMPLETE_GARRISON_SHIPMENT: + return "COMPLETE_GARRISON_SHIPMENT"; + case CRITERIA_TYPE_RAISE_GARRISON_FOLLOWER_ITEM_LEVEL: + return "RAISE_GARRISON_FOLLOWER_ITEM_LEVEL"; + case CRITERIA_TYPE_RAISE_GARRISON_FOLLOWER_LEVEL: + return "RAISE_GARRISON_FOLLOWER_LEVEL"; + case CRITERIA_TYPE_OWN_TOY: + return "OWN_TOY"; + case CRITERIA_TYPE_OWN_TOY_COUNT: + return "OWN_TOY_COUNT"; + case CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER: + return "RECRUIT_GARRISON_FOLLOWER"; + case CRITERIA_TYPE_OWN_HEIRLOOMS: + return "OWN_HEIRLOOMS"; + } + return "MISSING_TYPE"; +} + +CriteriaMgr* CriteriaMgr::Instance() +{ + static CriteriaMgr instance; + return &instance; +} + +//========================================================== +CriteriaMgr::~CriteriaMgr() +{ + for (auto itr = _criteriaTrees.begin(); itr != _criteriaTrees.end(); ++itr) + delete itr->second; + + for (auto itr = _criteria.begin(); itr != _criteria.end(); ++itr) + delete itr->second; + + for (auto itr = _criteriaModifiers.begin(); itr != _criteriaModifiers.end(); ++itr) + delete itr->second; +} + +void CriteriaMgr::LoadCriteriaModifiersTree() +{ + uint32 oldMSTime = getMSTime(); + + if (sModifierTreeStore.GetNumRows() == 0) + { + TC_LOG_ERROR("server.loading", ">> Loaded 0 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 criteria modifiers in %u ms", uint32(_criteriaModifiers.size()), GetMSTimeDiffToNow(oldMSTime)); +} + +template<typename T> +T GetEntry(std::unordered_map<uint32, T> const& map, CriteriaTreeEntry const* tree) +{ + CriteriaTreeEntry const* cur = tree; + auto itr = map.find(tree->ID); + while (itr == map.end()) + { + if (!cur->Parent) + break; + + cur = sCriteriaTreeStore.LookupEntry(cur->Parent); + if (!cur) + break; + + itr = map.find(cur->ID); + } + + if (itr == map.end()) + return nullptr; + + return itr->second; +}; + +void CriteriaMgr::LoadCriteriaList() +{ + uint32 oldMSTime = getMSTime(); + + if (sCriteriaTreeStore.GetNumRows() == 0) + { + TC_LOG_ERROR("server.loading", ">> Loaded 0 criteria."); + return; + } + + std::unordered_map<uint32 /*criteriaTreeID*/, AchievementEntry const*> achievementCriteriaTreeIds; + for (AchievementEntry const* achievement : sAchievementStore) + if (achievement->CriteriaTree) + achievementCriteriaTreeIds[achievement->CriteriaTree] = achievement; + + std::unordered_map<uint32 /*criteriaTreeID*/, ScenarioStepEntry const*> scenarioCriteriaTreeIds; + //for (ScenarioStepEntry const* scenarioStep : sScenarioStepStore) + // if (scenarioStep->CriteriaTreeID) + // scenarioCriteriaTreeIds[scenarioStep->CriteriaTreeID] = scenarioStep; + + // Load criteria tree nodes + for (CriteriaTreeEntry const* tree : sCriteriaTreeStore) + { + // Find linked achievement + AchievementEntry const* achievement = GetEntry(achievementCriteriaTreeIds, tree); + ScenarioStepEntry const* scenarioStep = GetEntry(scenarioCriteriaTreeIds, tree); + if (!achievement && !scenarioStep) + continue; + + CriteriaTree* criteriaTree = new CriteriaTree(); + criteriaTree->ID = tree->ID; + criteriaTree->Achievement = achievement; + criteriaTree->ScenarioStep = scenarioStep; + criteriaTree->Entry = tree; + + _criteriaTrees[criteriaTree->Entry->ID] = criteriaTree; + } + + // Build tree + for (auto itr = _criteriaTrees.begin(); itr != _criteriaTrees.end(); ++itr) + { + if (!itr->second->Entry->Parent) + continue; + + auto parent = _criteriaTrees.find(itr->second->Entry->Parent); + if (parent != _criteriaTrees.end()) + { + parent->second->Children.push_back(itr->second); + while (parent != _criteriaTrees.end()) + { + auto cur = parent; + parent = _criteriaTrees.find(parent->second->Entry->Parent); + if (parent == _criteriaTrees.end()) + { + if (sCriteriaStore.LookupEntry(itr->second->Entry->CriteriaID)) + _criteriaTreeByCriteria[itr->second->Entry->CriteriaID].push_back(cur->second); + } + } + } + else if (sCriteriaStore.LookupEntry(itr->second->Entry->CriteriaID)) + _criteriaTreeByCriteria[itr->second->Entry->CriteriaID].push_back(itr->second); + } + + // Load criteria + uint32 criterias = 0; + uint32 guildCriterias = 0; + uint32 scenarioCriterias = 0; + for (CriteriaEntry const* criteriaEntry : sCriteriaStore) + { + auto treeItr = _criteriaTreeByCriteria.find(criteriaEntry->ID); + if (treeItr == _criteriaTreeByCriteria.end()) + continue; + + Criteria* criteria = new Criteria(); + criteria->ID = criteriaEntry->ID; + criteria->Entry = criteriaEntry; + auto mod = _criteriaModifiers.find(criteriaEntry->ModifierTreeId); + if (mod != _criteriaModifiers.end()) + criteria->Modifier = mod->second; + + _criteria[criteria->ID] = criteria; + + for (CriteriaTree const* tree : treeItr->second) + { + if (AchievementEntry const* achievement = tree->Achievement) + { + if (achievement->Flags & ACHIEVEMENT_FLAG_GUILD) + criteria->FlagsCu |= CRITERIA_FLAG_CU_GUILD; + else if (achievement->Flags & ACHIEVEMENT_FLAG_ACCOUNT) + criteria->FlagsCu |= CRITERIA_FLAG_CU_ACCOUNT; + else + criteria->FlagsCu |= CRITERIA_FLAG_CU_PLAYER; + } + else if (tree->ScenarioStep) + criteria->FlagsCu |= CRITERIA_FLAG_CU_SCENARIO; + } + + if (criteria->FlagsCu & (CRITERIA_FLAG_CU_PLAYER | CRITERIA_FLAG_CU_ACCOUNT)) + { + ++criterias; + _criteriasByType[criteriaEntry->Type].push_back(criteria); + } + + if (criteria->FlagsCu & CRITERIA_FLAG_CU_GUILD) + { + ++guildCriterias; + _guildCriteriasByType[criteriaEntry->Type].push_back(criteria); + } + + if (criteria->FlagsCu & CRITERIA_FLAG_CU_SCENARIO) + { + ++scenarioCriterias; + _scenarioCriteriasByType[criteriaEntry->Type].push_back(criteria); + } + + if (criteriaEntry->StartTimer) + _criteriasByTimedType[criteriaEntry->StartEvent].push_back(criteria); + } + + for (auto& p : _criteriaTrees) + const_cast<CriteriaTree*>(p.second)->Criteria = GetCriteria(p.second->Entry->CriteriaID); + + TC_LOG_INFO("server.loading", ">> Loaded %u criteria, %u guild criteria and %u scenario criteria in %u ms.", criterias, guildCriterias, scenarioCriterias, GetMSTimeDiffToNow(oldMSTime)); +} + +void CriteriaMgr::LoadCriteriaData() +{ + uint32 oldMSTime = getMSTime(); + + _criteriaDataMap.clear(); // need for reload case + + QueryResult result = WorldDatabase.Query("SELECT criteria_id, type, value1, value2, ScriptName FROM criteria_data"); + + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 additional criteria data. DB table `criteria_data` is empty."); + return; + } + + uint32 count = 0; + + do + { + Field* fields = result->Fetch(); + uint32 criteria_id = fields[0].GetUInt32(); + + Criteria const* criteria = GetCriteria(criteria_id); + + if (!criteria) + { + TC_LOG_ERROR("sql.sql", "Table `criteria_data` contains data for non-existing criteria (Entry: %u). Ignored.", criteria_id); + continue; + } + + uint32 dataType = fields[1].GetUInt8(); + std::string scriptName = fields[4].GetString(); + uint32 scriptId = 0; + if (!scriptName.empty()) + { + if (dataType != CRITERIA_DATA_TYPE_SCRIPT) + TC_LOG_ERROR("sql.sql", "Table `criteria_data` contains a ScriptName for non-scripted data type (Entry: %u, type %u), useless data.", criteria_id, dataType); + else + scriptId = sObjectMgr->GetScriptId(scriptName); + } + + CriteriaData data(dataType, fields[2].GetUInt32(), fields[3].GetUInt32(), scriptId); + + if (!data.IsValid(criteria)) + continue; + + // this will allocate empty data set storage + CriteriaDataSet& dataSet = _criteriaDataMap[criteria_id]; + dataSet.SetCriteriaId(criteria_id); + + // add real data only for not NONE data types + if (data.DataType != CRITERIA_DATA_TYPE_NONE) + dataSet.Add(data); + + // counting data by and data types + ++count; + } + while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded %u additional criteria data in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); +} + +CriteriaTree const* CriteriaMgr::GetCriteriaTree(uint32 criteriaTreeId) const +{ + auto itr = _criteriaTrees.find(criteriaTreeId); + if (itr == _criteriaTrees.end()) + return nullptr; + + return itr->second; +} + +Criteria const* CriteriaMgr::GetCriteria(uint32 criteriaId) const +{ + auto itr = _criteria.find(criteriaId); + if (itr == _criteria.end()) + return nullptr; + + return itr->second; +} diff --git a/src/server/game/Achievements/CriteriaHandler.h b/src/server/game/Achievements/CriteriaHandler.h new file mode 100644 index 00000000000..0a12f5f6908 --- /dev/null +++ b/src/server/game/Achievements/CriteriaHandler.h @@ -0,0 +1,393 @@ +/* + * Copyright (C) 2008-2016 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 CriteriaHandler_h__ +#define CriteriaHandler_h__ + +#include "DBCEnums.h" +#include "ObjectGuid.h" +#include "Transaction.h" +#include "Common.h" + +class Player; +class Unit; +class WorldPacket; +struct AchievementEntry; +struct CriteriaEntry; +struct CriteriaTreeEntry; +struct ModifierTreeEntry; +struct ScenarioStepEntry; + +struct ModifierTreeNode +{ + ModifierTreeEntry const* Entry; + std::vector<ModifierTreeNode const*> Children; +}; + +enum CriteriaFlagsCu +{ + CRITERIA_FLAG_CU_PLAYER = 0x1, + CRITERIA_FLAG_CU_ACCOUNT = 0x2, + CRITERIA_FLAG_CU_GUILD = 0x4, + CRITERIA_FLAG_CU_SCENARIO = 0x8 +}; + +struct Criteria +{ + uint32 ID = 0; + CriteriaEntry const* Entry = nullptr; + ModifierTreeNode const* Modifier = nullptr; + uint32 FlagsCu = 0; +}; + +typedef std::vector<Criteria const*> CriteriaList; + +struct CriteriaTree +{ + uint32 ID = 0; + CriteriaTreeEntry const* Entry = nullptr; + AchievementEntry const* Achievement = nullptr; + ScenarioStepEntry const* ScenarioStep = nullptr; + Criteria const* Criteria = nullptr; + std::vector<CriteriaTree const*> Children; +}; + +typedef std::vector<CriteriaTree const*> CriteriaTreeList; + +struct CriteriaProgress +{ + uint64 Counter = 0; + std::time_t Date = std::time_t(0); // latest update time. + ObjectGuid PlayerGUID; // GUID of the player that last updated the criteria + bool Changed = false; +}; + +enum CriteriaDataType +{ // value1 value2 comment + CRITERIA_DATA_TYPE_NONE = 0, // 0 0 + CRITERIA_DATA_TYPE_T_CREATURE = 1, // CreatureId 0 + CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE = 2, // ClassId RaceId + CRITERIA_DATA_TYPE_T_PLAYER_LESS_HEALTH = 3, // HealthPercent 0 + CRITERIA_DATA_TYPE_S_AURA = 5, // SpellId EffectIndex + CRITERIA_DATA_TYPE_T_AURA = 7, // SpellId EffectIndex + CRITERIA_DATA_TYPE_VALUE = 8, // Minvalue value provided with update must be not less that limit + CRITERIA_DATA_TYPE_T_LEVEL = 9, // Minlevel minlevel of target + CRITERIA_DATA_TYPE_T_GENDER = 10, // Gender 0=male; 1=female + CRITERIA_DATA_TYPE_SCRIPT = 11, // Scripted requirement + // REUSE + CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT = 13, // Count "with less than %u people in the zone" + CRITERIA_DATA_TYPE_T_TEAM = 14, // Team HORDE(67), ALLIANCE(469) + CRITERIA_DATA_TYPE_S_DRUNK = 15, // DrunkenState 0 (enum DrunkenState) of player + CRITERIA_DATA_TYPE_HOLIDAY = 16, // HolidayId 0 event in holiday time + CRITERIA_DATA_TYPE_BG_LOSS_TEAM_SCORE = 17, // MinScore MaxScore player's team win bg and opposition team have team score in range + CRITERIA_DATA_TYPE_INSTANCE_SCRIPT = 18, // 0 0 maker instance script call for check current criteria requirements fit + CRITERIA_DATA_TYPE_S_EQUIPED_ITEM = 19, // ItemLevel Quality for equipped item in slot to check item level and quality + CRITERIA_DATA_TYPE_MAP_ID = 20, // MapId 0 player must be on map with id in map_id + CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE = 21, // Class Race + // REUSE + CRITERIA_DATA_TYPE_S_KNOWN_TITLE = 23, // TitleId known (pvp) title, values from dbc + CRITERIA_DATA_TYPE_GAME_EVENT = 24, // GameEventId 0 + + MAX_CRITERIA_DATA_TYPE +}; + +struct CriteriaData +{ + CriteriaDataType DataType; + union + { + // CRITERIA_DATA_TYPE_NONE = 0 (no data) + // CRITERIA_DATA_TYPE_T_CREATURE = 1 + struct + { + uint32 Id; + } Creature; + // CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE = 2 + // CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE = 21 + struct + { + uint32 Class; + uint32 Race; + } ClassRace; + // CRITERIA_DATA_TYPE_T_PLAYER_LESS_HEALTH = 3 + struct + { + uint32 Percent; + } Health; + // CRITERIA_DATA_TYPE_S_AURA = 5 + // CRITERIA_DATA_TYPE_T_AURA = 7 + struct + { + uint32 SpellId; + uint32 EffectIndex; + } Aura; + // CRITERIA_DATA_TYPE_VALUE = 8 + struct + { + uint32 Value; + uint32 ComparisonType; + } Value; + // CRITERIA_DATA_TYPE_T_LEVEL = 9 + struct + { + uint32 Min; + } Level; + // CRITERIA_DATA_TYPE_T_GENDER = 10 + struct + { + uint32 Gender; + } Gender; + // CRITERIA_DATA_TYPE_SCRIPT = 11 (no data) + // CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT = 13 + struct + { + uint32 MaxCount; + } MapPlayers; + // CRITERIA_DATA_TYPE_T_TEAM = 14 + struct + { + uint32 Team; + } Team; + // CRITERIA_DATA_TYPE_S_DRUNK = 15 + struct + { + uint32 State; + } Drunk; + // CRITERIA_DATA_TYPE_HOLIDAY = 16 + struct + { + uint32 Id; + } Holiday; + // CRITERIA_DATA_TYPE_BG_LOSS_TEAM_SCORE= 17 + struct + { + uint32 Min; + uint32 Max; + } BattlegroundScore; + // CRITERIA_DATA_TYPE_INSTANCE_SCRIPT = 18 (no data) + // CRITERIA_DATA_TYPE_S_EQUIPED_ITEM = 19 + struct + { + uint32 ItemLevel; + uint32 Quality; + } EquippedItem; + // CRITERIA_DATA_TYPE_MAP_ID = 20 + struct + { + uint32 Id; + } Map; + // CRITERIA_DATA_TYPE_KNOWN_TITLE = 22 + struct + { + uint32 Id; + } KnownTitle; + // CRITERIA_DATA_TYPE_GAME_EVENT = 24 + struct + { + uint32 Id; + } GameEvent; + // raw + struct + { + uint32 Value1; + uint32 Value2; + } Raw; + }; + uint32 ScriptId; + + CriteriaData() : DataType(CRITERIA_DATA_TYPE_NONE) + { + Raw.Value1 = 0; + Raw.Value2 = 0; + ScriptId = 0; + } + + CriteriaData(uint32 _dataType, uint32 _value1, uint32 _value2, uint32 _scriptId) : DataType(CriteriaDataType(_dataType)) + { + Raw.Value1 = _value1; + Raw.Value2 = _value2; + ScriptId = _scriptId; + } + + bool IsValid(Criteria const* criteria); + bool Meets(uint32 criteriaId, Player const* source, Unit const* target, uint32 miscValue1 = 0) const; +}; + +struct CriteriaDataSet +{ + CriteriaDataSet() : _criteriaId(0) { } + void Add(CriteriaData const& data) { _storage.push_back(data); } + bool Meets(Player const* source, Unit const* target, uint32 miscValue = 0) const; + void SetCriteriaId(uint32 id) { _criteriaId = id; } +private: + uint32 _criteriaId; + std::vector<CriteriaData> _storage; +}; + +typedef std::map<uint32, CriteriaDataSet> CriteriaDataMap; +typedef std::unordered_map<uint32, CriteriaProgress> CriteriaProgressMap; + +enum ProgressType +{ + PROGRESS_SET, + PROGRESS_ACCUMULATE, + PROGRESS_HIGHEST +}; + +class TC_GAME_API CriteriaHandler +{ +public: + CriteriaHandler(); + virtual ~CriteriaHandler(); + + virtual void Reset(); + + void UpdateCriteria(CriteriaTypes type, uint64 miscValue1 = 0, uint64 miscValue2 = 0, uint64 miscValue3 = 0, Unit const* unit = nullptr, Player* referencePlayer = nullptr); + + virtual void SendAllData(Player const* receiver) const = 0; + + void UpdateTimedCriteria(uint32 timeDiff); + void StartCriteriaTimer(CriteriaTimedTypes type, uint32 entry, uint32 timeLost = 0); + void RemoveCriteriaTimer(CriteriaTimedTypes type, uint32 entry); // used for quest and scripted timed s + +protected: + virtual void SendCriteriaUpdate(Criteria const* criteria, CriteriaProgress const* progress, uint32 timeElapsed, bool timedCompleted) const = 0; + + CriteriaProgress* GetCriteriaProgress(Criteria const* entry); + void SetCriteriaProgress(Criteria const* criteria, uint64 changeValue, Player* referencePlayer, ProgressType progressType = PROGRESS_SET); + void RemoveCriteriaProgress(Criteria const* criteria); + virtual void SendCriteriaProgressRemoved(uint32 criteriaId) = 0; + + bool IsCompletedCriteriaTree(CriteriaTree const* tree); + virtual bool CanUpdateCriteriaTree(Criteria const* criteria, CriteriaTree const* tree, Player* referencePlayer) const = 0; + virtual bool CanCompleteCriteriaTree(CriteriaTree const* tree); + virtual void CompletedCriteriaTree(CriteriaTree const* tree, Player* referencePlayer) = 0; + virtual void AfterCriteriaTreeUpdate(CriteriaTree const* /*tree*/, Player* /*referencePlayer*/) { } + + bool IsCompletedCriteria(Criteria const* criteria, uint64 requiredAmount); + bool CanUpdateCriteria(Criteria const* criteria, CriteriaTreeList const* trees, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit const* unit, Player* referencePlayer); + + virtual void SendPacket(WorldPacket const* data) const = 0; + + bool ConditionsSatisfied(Criteria const* criteria, Player* referencePlayer) const; + bool RequirementsSatisfied(Criteria const* criteria, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit const* unit, Player* referencePlayer) const; + virtual bool RequiredAchievementSatisfied(uint32 /*achievementId*/) const { return false; } + bool AdditionalRequirementsSatisfied(ModifierTreeNode const* parent, uint64 miscValue1, uint64 miscValue2, Unit const* unit, Player* referencePlayer) const; + + virtual std::string GetOwnerInfo() const = 0; + virtual CriteriaList const& GetCriteriaByType(CriteriaTypes type) const = 0; + + CriteriaProgressMap _criteriaProgress; + std::map<uint32, uint32 /*ms time left*/> _timeCriteriaTrees; +}; + +class TC_GAME_API CriteriaMgr +{ + CriteriaMgr() { } + ~CriteriaMgr(); + +public: + static char const* GetCriteriaTypeString(CriteriaTypes type); + static char const* GetCriteriaTypeString(uint32 type); + + static CriteriaMgr* Instance(); + + CriteriaList const& GetPlayerCriteriaByType(CriteriaTypes type) const + { + return _criteriasByType[type]; + } + + CriteriaList const& GetGuildCriteriaByType(CriteriaTypes type) const + { + return _guildCriteriasByType[type]; + } + + CriteriaList const& GetScenarioCriteriaByType(CriteriaTypes type) const + { + return _scenarioCriteriasByType[type]; + } + + CriteriaTreeList const* GetCriteriaTreesByCriteria(uint32 criteriaId) const + { + auto itr = _criteriaTreeByCriteria.find(criteriaId); + return itr != _criteriaTreeByCriteria.end() ? &itr->second : nullptr; + } + + CriteriaList const& GetTimedCriteriaByType(CriteriaTimedTypes type) const + { + return _criteriasByTimedType[type]; + } + + CriteriaDataSet const* GetCriteriaDataSet(Criteria const* Criteria) const + { + CriteriaDataMap::const_iterator iter = _criteriaDataMap.find(Criteria->ID); + return iter != _criteriaDataMap.end() ? &iter->second : NULL; + } + + static bool IsGroupCriteriaType(CriteriaTypes type) + { + switch (type) + { + case CRITERIA_TYPE_KILL_CREATURE: + case CRITERIA_TYPE_WIN_BG: + case CRITERIA_TYPE_BE_SPELL_TARGET: // NYI + case CRITERIA_TYPE_WIN_RATED_ARENA: + case CRITERIA_TYPE_BE_SPELL_TARGET2: // NYI + case CRITERIA_TYPE_WIN_RATED_BATTLEGROUND: // NYI + return true; + default: + break; + } + + return false; + } + + template<typename Func> + static void WalkCriteriaTree(CriteriaTree const* tree, Func const& func) + { + for (CriteriaTree const* node : tree->Children) + WalkCriteriaTree(node, func); + + func(tree); + } + + void LoadCriteriaModifiersTree(); + void LoadCriteriaList(); + void LoadCriteriaData(); + CriteriaTree const* GetCriteriaTree(uint32 criteriaTreeId) const; + Criteria const* GetCriteria(uint32 criteriaId) const; + +private: + CriteriaDataMap _criteriaDataMap; + + std::unordered_map<uint32, CriteriaTree*> _criteriaTrees; + std::unordered_map<uint32, Criteria*> _criteria; + std::unordered_map<uint32, ModifierTreeNode*> _criteriaModifiers; + + std::unordered_map<uint32, CriteriaTreeList> _criteriaTreeByCriteria; + + // store criterias by type to speed up lookup + CriteriaList _criteriasByType[CRITERIA_TYPE_TOTAL]; + CriteriaList _guildCriteriasByType[CRITERIA_TYPE_TOTAL]; + CriteriaList _scenarioCriteriasByType[CRITERIA_TYPE_TOTAL]; + + CriteriaList _criteriasByTimedType[CRITERIA_TIMED_TYPE_MAX]; +}; + +#define sCriteriaMgr CriteriaMgr::Instance() + +#endif // CriteriaHandler_h__ diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp index 1ea1099cd96..b937f2194e2 100644 --- a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp +++ b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp @@ -157,7 +157,7 @@ void AuctionHouseMgr::SendAuctionWonMail(AuctionEntry* auction, SQLTransaction& { bidder->GetSession()->SendAuctionWonNotification(auction, item); // FIXME: for offline player need also - bidder->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS, 1); + bidder->UpdateCriteria(CRITERIA_TYPE_WON_AUCTIONS, 1); } MailDraft(auction->BuildAuctionMailSubject(AUCTION_WON), AuctionEntry::BuildAuctionMailBody(auction->owner, auction->bid, auction->buyout, 0, 0)) @@ -198,8 +198,8 @@ void AuctionHouseMgr::SendAuctionSuccessfulMail(AuctionEntry* auction, SQLTransa //FIXME: what do if owner offline if (owner && item) { - owner->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS, profit); - owner->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD, auction->bid); + owner->UpdateCriteria(CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS, profit); + owner->UpdateCriteria(CRITERIA_TYPE_HIGHEST_AUCTION_SOLD, auction->bid); //send auction owner notification, bidder must be current! owner->GetSession()->SendAuctionClosedNotification(auction, (float)sWorld->getIntConfig(CONFIG_MAIL_DELIVERY_DELAY), true, item); } diff --git a/src/server/game/BattlePets/BattlePetMgr.cpp b/src/server/game/BattlePets/BattlePetMgr.cpp index 1ee8e8f9a3a..52adbd4d976 100644 --- a/src/server/game/BattlePets/BattlePetMgr.cpp +++ b/src/server/game/BattlePets/BattlePetMgr.cpp @@ -333,7 +333,7 @@ void BattlePetMgr::AddPet(uint32 species, uint32 creatureId, uint16 breed, uint8 updates.push_back(pet); SendUpdates(updates, true); - _owner->GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_OWN_BATTLE_PET, species); + _owner->GetPlayer()->UpdateCriteria(CRITERIA_TYPE_OWN_BATTLE_PET, species); } void BattlePetMgr::RemovePet(ObjectGuid guid) diff --git a/src/server/game/Battlefield/Zones/BattlefieldWG.cpp b/src/server/game/Battlefield/Zones/BattlefieldWG.cpp index 48db5704f8e..4cb37624cf6 100644 --- a/src/server/game/Battlefield/Zones/BattlefieldWG.cpp +++ b/src/server/game/Battlefield/Zones/BattlefieldWG.cpp @@ -414,7 +414,7 @@ void BattlefieldWG::OnBattleEnd(bool endByTimer) // ******************************************************* void BattlefieldWG::DoCompleteOrIncrementAchievement(uint32 achievement, Player* player, uint8 /*incrementNumber*/) { - AchievementEntry const* achievementEntry = sAchievementMgr->GetAchievement(achievement); + AchievementEntry const* achievementEntry = sAchievementStore.LookupEntry(achievement); if (!achievementEntry) return; @@ -423,7 +423,7 @@ void BattlefieldWG::DoCompleteOrIncrementAchievement(uint32 achievement, Player* { case ACHIEVEMENTS_WIN_WG_100: { - // player->UpdateAchievementCriteria(); + // player->UpdateCriteria(); } default: { diff --git a/src/server/game/Battlegrounds/Arena.cpp b/src/server/game/Battlegrounds/Arena.cpp index 33b765b1930..8e101e71923 100644 --- a/src/server/game/Battlegrounds/Arena.cpp +++ b/src/server/game/Battlegrounds/Arena.cpp @@ -222,8 +222,8 @@ void Arena::EndBattleground(uint32 winner) { // update achievement BEFORE personal rating update uint32 rating = player->GetArenaPersonalRating(winnerArenaTeam->GetSlot()); - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA, rating ? rating : 1); - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA, GetMapId()); + player->UpdateCriteria(CRITERIA_TYPE_WIN_RATED_ARENA, rating ? rating : 1); + player->UpdateCriteria(CRITERIA_TYPE_WIN_ARENA, GetMapId()); player->ModifyCurrency(CURRENCY_TYPE_CONQUEST_META_ARENA, sWorld->getIntConfig(CONFIG_CURRENCY_CONQUEST_POINTS_ARENA_REWARD)); // Last standing - Rated 5v5 arena & be solely alive player @@ -235,7 +235,7 @@ void Arena::EndBattleground(uint32 winner) guildAwarded = true; if (ObjectGuid::LowType guildId = GetBgMap()->GetOwnerGuildId(player->GetBGTeam())) if (Guild* guild = sGuildMgr->GetGuildById(guildId)) - guild->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA, std::max<uint32>(winnerArenaTeam->GetRating(), 1), 0, 0, NULL, player); + guild->UpdateCriteria(CRITERIA_TYPE_WIN_RATED_ARENA, std::max<uint32>(winnerArenaTeam->GetRating(), 1), 0, 0, NULL, player); } winnerArenaTeam->MemberWon(player, loserMatchmakerRating, winnerMatchmakerChange); @@ -245,7 +245,7 @@ void Arena::EndBattleground(uint32 winner) loserArenaTeam->MemberLost(player, winnerMatchmakerRating, loserMatchmakerChange); // Arena lost => reset the win_rated_arena having the "no_lose" condition - player->ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA, ACHIEVEMENT_CRITERIA_CONDITION_NO_LOSE); + player->ResetCriteria(CRITERIA_TYPE_WIN_RATED_ARENA, CRITERIA_CONDITION_NO_LOSE); } } diff --git a/src/server/game/Battlegrounds/ArenaTeam.cpp b/src/server/game/Battlegrounds/ArenaTeam.cpp index 8e7c4fd0258..23eb6843fb3 100644 --- a/src/server/game/Battlegrounds/ArenaTeam.cpp +++ b/src/server/game/Battlegrounds/ArenaTeam.cpp @@ -436,7 +436,7 @@ void ArenaTeamMember::ModifyPersonalRating(Player* player, int32 mod, uint32 typ if (player) { player->SetArenaTeamInfoField(ArenaTeam::GetSlotByType(type), ARENA_TEAM_PERSONAL_RATING, PersonalRating); - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_PERSONAL_RATING, PersonalRating, type); + player->UpdateCriteria(CRITERIA_TYPE_HIGHEST_PERSONAL_RATING, PersonalRating, type); } } @@ -597,7 +597,7 @@ void ArenaTeam::FinishGame(int32 mod) // Check if rating related achivements are met for (MemberList::iterator itr = Members.begin(); itr != Members.end(); ++itr) if (Player* member = ObjectAccessor::FindConnectedPlayer(itr->Guid)) - member->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING, Stats.Rating, Type); + member->UpdateCriteria(CRITERIA_TYPE_HIGHEST_TEAM_RATING, Stats.Rating, Type); } // Update number of games played per season or week diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index 5347915fb39..0051f0698d9 100644 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -869,14 +869,14 @@ void Battleground::EndBattleground(uint32 winner) else // 50cp awarded for each non-rated battleground won player->ModifyCurrency(CURRENCY_TYPE_CONQUEST_META_ARENA, sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_CONQUEST_LAST)); - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_BG, 1); + player->UpdateCriteria(CRITERIA_TYPE_WIN_BG, 1); if (!guildAwarded) { guildAwarded = true; if (ObjectGuid::LowType guildId = GetBgMap()->GetOwnerGuildId(player->GetBGTeam())) { if (Guild* guild = sGuildMgr->GetGuildById(guildId)) - guild->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_BG, 1, 0, 0, NULL, player); + guild->UpdateCriteria(CRITERIA_TYPE_WIN_BG, 1, 0, 0, NULL, player); } } } @@ -897,7 +897,7 @@ void Battleground::EndBattleground(uint32 winner) sBattlegroundMgr->BuildBattlegroundStatusActive(&battlefieldStatus, this, player, player->GetBattlegroundQueueIndex(bgQueueTypeId), player->GetBattlegroundQueueJoinTime(bgQueueTypeId), GetArenaType()); player->SendDirectMessage(battlefieldStatus.Write()); - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND, 1); + player->UpdateCriteria(CRITERIA_TYPE_COMPLETE_BATTLEGROUND, 1); } if (winmsg_id) @@ -1138,17 +1138,17 @@ void Battleground::AddPlayer(Player* player) } } - player->ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP, GetMapId(), true); - player->ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_BG, ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP, GetMapId(), true); - player->ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE, ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP, GetMapId(), true); - player->ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP, GetMapId(), true); - player->ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL, ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP, GetMapId(), true); - player->ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP, GetMapId(), true); - player->ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA, ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP, GetMapId(), true); - player->ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL, ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP, GetMapId(), true); - player->ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE, ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP, GetMapId(), true); - player->ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS, ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP, GetMapId(), true); - player->ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL, ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP, GetMapId(), true); + player->ResetCriteria(CRITERIA_TYPE_KILL_CREATURE, CRITERIA_CONDITION_BG_MAP, GetMapId(), true); + player->ResetCriteria(CRITERIA_TYPE_WIN_BG, CRITERIA_CONDITION_BG_MAP, GetMapId(), true); + player->ResetCriteria(CRITERIA_TYPE_DAMAGE_DONE, CRITERIA_CONDITION_BG_MAP, GetMapId(), true); + player->ResetCriteria(CRITERIA_TYPE_BE_SPELL_TARGET, CRITERIA_CONDITION_BG_MAP, GetMapId(), true); + player->ResetCriteria(CRITERIA_TYPE_CAST_SPELL, CRITERIA_CONDITION_BG_MAP, GetMapId(), true); + player->ResetCriteria(CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, CRITERIA_CONDITION_BG_MAP, GetMapId(), true); + player->ResetCriteria(CRITERIA_TYPE_HONORABLE_KILL_AT_AREA, CRITERIA_CONDITION_BG_MAP, GetMapId(), true); + player->ResetCriteria(CRITERIA_TYPE_HONORABLE_KILL, CRITERIA_CONDITION_BG_MAP, GetMapId(), true); + player->ResetCriteria(CRITERIA_TYPE_HEALING_DONE, CRITERIA_CONDITION_BG_MAP, GetMapId(), true); + player->ResetCriteria(CRITERIA_TYPE_GET_KILLING_BLOWS, CRITERIA_CONDITION_BG_MAP, GetMapId(), true); + player->ResetCriteria(CRITERIA_TYPE_SPECIAL_PVP_KILL, CRITERIA_CONDITION_BG_MAP, GetMapId(), true); // setup BG group membership PlayerAddedToBGCheckIfBGIsRunning(player); @@ -1902,11 +1902,11 @@ WorldSafeLocsEntry const* Battleground::GetClosestGraveYard(Player* player) return sObjectMgr->GetClosestGraveYard(player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetMapId(), player->GetTeam()); } -void Battleground::StartTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry) +void Battleground::StartCriteriaTimer(CriteriaTimedTypes type, uint32 entry) { for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) if (Player* player = ObjectAccessor::FindPlayer(itr->first)) - player->StartTimedAchievement(type, entry); + player->StartCriteriaTimer(type, entry); } void Battleground::SetBracket(PvPDifficultyEntry const* bracketEntry) diff --git a/src/server/game/Battlegrounds/Battleground.h b/src/server/game/Battlegrounds/Battleground.h index cb2fb68d9dd..2ef7eca4aa1 100644 --- a/src/server/game/Battlegrounds/Battleground.h +++ b/src/server/game/Battlegrounds/Battleground.h @@ -253,7 +253,7 @@ class TC_GAME_API Battleground /* achievement req. */ virtual bool IsAllNodesControlledByTeam(uint32 /*team*/) const { return false; } - void StartTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry); + void StartCriteriaTimer(CriteriaTimedTypes type, uint32 entry); virtual bool CheckAchievementCriteriaMeet(uint32 /*criteriaId*/, Player const* /*player*/, Unit const* /*target*/ = NULL, uint32 /*miscvalue1*/ = 0); /* Battleground */ diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp index d3083da8734..911fe259fc3 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp @@ -216,7 +216,7 @@ void BattlegroundAB::StartingEventOpenDoors() DoorOpen(BG_AB_OBJECT_GATE_H); // Achievement: Let's Get This Done - StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, AB_EVENT_START_BATTLE); + StartCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, AB_EVENT_START_BATTLE); } void BattlegroundAB::AddPlayer(Player* player) @@ -698,10 +698,10 @@ bool BattlegroundAB::UpdatePlayerScore(Player* player, uint32 type, uint32 value switch (type) { case SCORE_BASES_ASSAULTED: - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AB_OBJECTIVE_ASSAULT_BASE); + player->UpdateCriteria(CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AB_OBJECTIVE_ASSAULT_BASE); break; case SCORE_BASES_DEFENDED: - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AB_OBJECTIVE_DEFEND_BASE); + player->UpdateCriteria(CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AB_OBJECTIVE_DEFEND_BASE); break; default: break; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp index 80dfd1e4aeb..59d01df8237 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp @@ -429,7 +429,7 @@ void BattlegroundAV::StartingEventOpenDoors() DoorOpen(BG_AV_OBJECT_DOOR_A); // Achievement: The Alterac Blitz - StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, BG_AV_EVENT_START_BATTLE); + StartCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, BG_AV_EVENT_START_BATTLE); } void BattlegroundAV::AddPlayer(Player* player) @@ -533,16 +533,16 @@ bool BattlegroundAV::UpdatePlayerScore(Player* player, uint32 type, uint32 value switch (type) { case SCORE_GRAVEYARDS_ASSAULTED: - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AV_OBJECTIVE_ASSAULT_GRAVEYARD); + player->UpdateCriteria(CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AV_OBJECTIVE_ASSAULT_GRAVEYARD); break; case SCORE_GRAVEYARDS_DEFENDED: - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AV_OBJECTIVE_DEFEND_GRAVEYARD); + player->UpdateCriteria(CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AV_OBJECTIVE_DEFEND_GRAVEYARD); break; case SCORE_TOWERS_ASSAULTED: - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AV_OBJECTIVE_ASSAULT_TOWER); + player->UpdateCriteria(CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AV_OBJECTIVE_ASSAULT_TOWER); break; case SCORE_TOWERS_DEFENDED: - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AV_OBJECTIVE_DEFEND_TOWER); + player->UpdateCriteria(CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, AV_OBJECTIVE_DEFEND_TOWER); break; default: break; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp index d2922ff0164..461420fe962 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp @@ -153,7 +153,7 @@ void BattlegroundEY::StartingEventOpenDoors() } // Achievement: Flurry - StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, BG_EY_EVENT_START_BATTLE); + StartCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, BG_EY_EVENT_START_BATTLE); } void BattlegroundEY::AddPoints(uint32 Team, uint32 Points) @@ -849,7 +849,7 @@ bool BattlegroundEY::UpdatePlayerScore(Player* player, uint32 type, uint32 value switch (type) { case SCORE_FLAG_CAPTURES: - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, EY_OBJECTIVE_CAPTURE_FLAG); + player->UpdateCriteria(CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, EY_OBJECTIVE_CAPTURE_FLAG); break; default: break; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp index 149d914d128..032b283727c 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp @@ -343,7 +343,7 @@ void BattlegroundSA::PostUpdateImpl(uint32 diff) ToggleTimer(); DemolisherStartState(false); Status = BG_SA_ROUND_ONE; - StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, (Attackers == TEAM_ALLIANCE) ? 23748 : 21702); + StartCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, (Attackers == TEAM_ALLIANCE) ? 23748 : 21702); } if (TotalTime >= BG_SA_BOAT_START) StartShips(); @@ -365,7 +365,7 @@ void BattlegroundSA::PostUpdateImpl(uint32 diff) ToggleTimer(); DemolisherStartState(false); Status = BG_SA_ROUND_TWO; - StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, (Attackers == TEAM_ALLIANCE) ? 23748 : 21702); + StartCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, (Attackers == TEAM_ALLIANCE) ? 23748 : 21702); // status was set to STATUS_WAIT_JOIN manually for Preparation, set it back now SetStatus(STATUS_IN_PROGRESS); for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) @@ -907,7 +907,7 @@ void BattlegroundSA::TitanRelicActivated(Player* clicker) { if (Player* player = ObjectAccessor::FindPlayer(itr->first)) if (player->GetTeamId() == Attackers) - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, 65246); + player->UpdateCriteria(CRITERIA_TYPE_BE_SPELL_TARGET, 65246); } Attackers = (Attackers == TEAM_ALLIANCE) ? TEAM_HORDE : TEAM_ALLIANCE; @@ -937,7 +937,7 @@ void BattlegroundSA::TitanRelicActivated(Player* clicker) { if (Player* player = ObjectAccessor::FindPlayer(itr->first)) if (player->GetTeamId() == Attackers && RoundScores[1].winner == Attackers) - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, 65246); + player->UpdateCriteria(CRITERIA_TYPE_BE_SPELL_TARGET, 65246); } if (RoundScores[0].time == RoundScores[1].time) diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp index 2c9c43826ce..0df4fd6f88e 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp @@ -245,7 +245,7 @@ void BattlegroundWS::StartingEventOpenDoors() SpawnBGObject(BG_WS_OBJECT_DOOR_H_4, RESPAWN_ONE_DAY); // players joining later are not eligibles - StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, WS_EVENT_START_BATTLE); + StartCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, WS_EVENT_START_BATTLE); } void BattlegroundWS::AddPlayer(Player* player) @@ -504,7 +504,7 @@ void BattlegroundWS::EventPlayerClickedOnFlag(Player* player, GameObject* target UpdateFlagState(HORDE, BG_WS_FLAG_STATE_ON_PLAYER); UpdateWorldState(BG_WS_FLAG_UNK_ALLIANCE, 1); player->CastSpell(player, BG_WS_SPELL_SILVERWING_FLAG, true); - player->StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_SPELL_TARGET, BG_WS_SPELL_SILVERWING_FLAG_PICKED); + player->StartCriteriaTimer(CRITERIA_TIMED_TYPE_SPELL_TARGET, BG_WS_SPELL_SILVERWING_FLAG_PICKED); if (_flagState[1] == BG_WS_FLAG_STATE_ON_PLAYER) _bothFlagsKept = true; } @@ -523,7 +523,7 @@ void BattlegroundWS::EventPlayerClickedOnFlag(Player* player, GameObject* target UpdateFlagState(ALLIANCE, BG_WS_FLAG_STATE_ON_PLAYER); UpdateWorldState(BG_WS_FLAG_UNK_HORDE, 1); player->CastSpell(player, BG_WS_SPELL_WARSONG_FLAG, true); - player->StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_SPELL_TARGET, BG_WS_SPELL_WARSONG_FLAG_PICKED); + player->StartCriteriaTimer(CRITERIA_TIMED_TYPE_SPELL_TARGET, BG_WS_SPELL_WARSONG_FLAG_PICKED); if (_flagState[0] == BG_WS_FLAG_STATE_ON_PLAYER) _bothFlagsKept = true; } @@ -817,10 +817,10 @@ bool BattlegroundWS::UpdatePlayerScore(Player* player, uint32 type, uint32 value switch (type) { case SCORE_FLAG_CAPTURES: // flags captured - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, WS_OBJECTIVE_CAPTURE_FLAG); + player->UpdateCriteria(CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, WS_OBJECTIVE_CAPTURE_FLAG); break; case SCORE_FLAG_RETURNS: // flags returned - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, WS_OBJECTIVE_RETURN_FLAG); + player->UpdateCriteria(CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, WS_OBJECTIVE_RETURN_FLAG); break; default: break; diff --git a/src/server/game/Chat/ChatLink.cpp b/src/server/game/Chat/ChatLink.cpp index 4eeea1b20cb..3e523cad4fb 100644 --- a/src/server/game/Chat/ChatLink.cpp +++ b/src/server/game/Chat/ChatLink.cpp @@ -379,7 +379,7 @@ bool AchievementChatLink::Initialize(std::istringstream& iss) return false; } // Validate achievement - _achievement = sAchievementMgr->GetAchievement(achievementId); + _achievement = sAchievementStore.LookupEntry(achievementId); if (!_achievement) { TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got invalid achivement id %u in |achievement command", iss.str().c_str(), achievementId); diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index 002f4040255..4a0fa1984aa 100644 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -425,8 +425,8 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) const } case CONDITION_REALM_ACHIEVEMENT: { - AchievementEntry const* achievement = sAchievementMgr->GetAchievement(ConditionValue1); - if (achievement && sAchievementMgr->IsRealmCompleted(achievement, std::numeric_limits<uint32>::max())) + AchievementEntry const* achievement = sAchievementStore.LookupEntry(ConditionValue1); + if (achievement && sAchievementMgr->IsRealmCompleted(achievement)) condMeets = true; break; } @@ -1908,7 +1908,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) const } case CONDITION_ACHIEVEMENT: { - AchievementEntry const* achievement = sAchievementMgr->GetAchievement(cond->ConditionValue1); + AchievementEntry const* achievement = sAchievementStore.LookupEntry(cond->ConditionValue1); if (!achievement) { TC_LOG_ERROR("sql.sql", "%s has non existing achivement id (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1); @@ -2211,7 +2211,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) const break; case CONDITION_REALM_ACHIEVEMENT: { - AchievementEntry const* achievement = sAchievementMgr->GetAchievement(cond->ConditionValue1); + AchievementEntry const* achievement = sAchievementStore.LookupEntry(cond->ConditionValue1); if (!achievement) { TC_LOG_ERROR("sql.sql", "%s has non existing realm first achivement id (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1); diff --git a/src/server/game/Conditions/DisableMgr.cpp b/src/server/game/Conditions/DisableMgr.cpp index cf5b672384b..62d5ecfa88a 100644 --- a/src/server/game/Conditions/DisableMgr.cpp +++ b/src/server/game/Conditions/DisableMgr.cpp @@ -17,7 +17,7 @@ */ #include "DisableMgr.h" -#include "AchievementMgr.h" +#include "CriteriaHandler.h" #include "ObjectMgr.h" #include "OutdoorPvP.h" #include "SpellMgr.h" @@ -183,14 +183,14 @@ void LoadDisables() if (flags) TC_LOG_ERROR("sql.sql", "Disable flags specified for outdoor PvP %u, useless data.", entry); break; - case DISABLE_TYPE_ACHIEVEMENT_CRITERIA: - if (!sAchievementMgr->GetAchievementCriteria(entry)) + case DISABLE_TYPE_CRITERIA: + if (!sCriteriaMgr->GetCriteria(entry)) { - TC_LOG_ERROR("sql.sql", "Achievement Criteria entry %u from `disables` doesn't exist in dbc, skipped.", entry); + TC_LOG_ERROR("sql.sql", "Criteria entry %u from `disables` doesn't exist in dbc, skipped.", entry); continue; } if (flags) - TC_LOG_ERROR("sql.sql", "Disable flags specified for Achievement Criteria %u, useless data.", entry); + TC_LOG_ERROR("sql.sql", "Disable flags specified for Criteria %u, useless data.", entry); break; case DISABLE_TYPE_VMAP: { @@ -362,7 +362,7 @@ bool IsDisabledFor(DisableType type, uint32 entry, Unit const* unit, uint8 flags return true; case DISABLE_TYPE_BATTLEGROUND: case DISABLE_TYPE_OUTDOORPVP: - case DISABLE_TYPE_ACHIEVEMENT_CRITERIA: + case DISABLE_TYPE_CRITERIA: case DISABLE_TYPE_MMAP: return true; case DISABLE_TYPE_VMAP: diff --git a/src/server/game/Conditions/DisableMgr.h b/src/server/game/Conditions/DisableMgr.h index cae1e0329e8..95e54932f15 100644 --- a/src/server/game/Conditions/DisableMgr.h +++ b/src/server/game/Conditions/DisableMgr.h @@ -30,7 +30,7 @@ enum DisableType DISABLE_TYPE_QUEST = 1, DISABLE_TYPE_MAP = 2, DISABLE_TYPE_BATTLEGROUND = 3, - DISABLE_TYPE_ACHIEVEMENT_CRITERIA = 4, + DISABLE_TYPE_CRITERIA = 4, DISABLE_TYPE_OUTDOORPVP = 5, DISABLE_TYPE_VMAP = 6, DISABLE_TYPE_MMAP = 7 diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h index a6774b03684..daebcf7375f 100644 --- a/src/server/game/DataStores/DB2Structure.h +++ b/src/server/game/DataStores/DB2Structure.h @@ -188,120 +188,120 @@ struct CriteriaEntry union { uint32 ID; - // ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE = 0 - // ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE = 20 + // CRITERIA_TYPE_KILL_CREATURE = 0 + // 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 + // CRITERIA_TYPE_WIN_BG = 1 + // CRITERIA_TYPE_COMPLETE_BATTLEGROUND = 15 + // CRITERIA_TYPE_DEATH_AT_MAP = 16 + // CRITERIA_TYPE_WIN_ARENA = 32 + // 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 + // CRITERIA_TYPE_REACH_SKILL_LEVEL = 7 + // CRITERIA_TYPE_LEARN_SKILL_LEVEL = 40 + // CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS = 75 + // CRITERIA_TYPE_LEARN_SKILL_LINE = 112 uint32 SkillID; - // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT = 8 + // CRITERIA_TYPE_COMPLETE_ACHIEVEMENT = 8 uint32 AchievementID; - // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE = 11 + // CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE = 11 uint32 ZoneID; - // ACHIEVEMENT_CRITERIA_TYPE_CURRENCY = 12 + // CRITERIA_TYPE_CURRENCY = 12 uint32 CurrencyID; - // ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON = 18 - // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID = 19 + // CRITERIA_TYPE_DEATH_IN_DUNGEON = 18 + // CRITERIA_TYPE_COMPLETE_RAID = 19 uint32 GroupSize; - // ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM = 26 + // CRITERIA_TYPE_DEATHS_FROM = 26 uint32 DamageType; - // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST = 27 + // 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 + // CRITERIA_TYPE_BE_SPELL_TARGET = 28 + // CRITERIA_TYPE_BE_SPELL_TARGET2 = 69 + // CRITERIA_TYPE_CAST_SPELL = 29 + // CRITERIA_TYPE_CAST_SPELL2 = 110 + // CRITERIA_TYPE_LEARN_SPELL = 34 uint32 SpellID; - // ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE + // CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE uint32 ObjectiveId; - // ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA = 31 - // ACHIEVEMENT_CRITERIA_TYPE_ENTER_AREA = 163 - // ACHIEVEMENT_CRITERIA_TYPE_LEAVE_AREA = 164 + // CRITERIA_TYPE_HONORABLE_KILL_AT_AREA = 31 + // CRITERIA_TYPE_ENTER_AREA = 163 + // CRITERIA_TYPE_LEAVE_AREA = 164 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 - // ACHIEVEMENT_CRITERIA_TYPE_OWN_TOY = 185 + // CRITERIA_TYPE_OWN_ITEM = 36 + // CRITERIA_TYPE_USE_ITEM = 41 + // CRITERIA_TYPE_LOOT_ITEM = 42 + // CRITERIA_TYPE_EQUIP_ITEM = 57 + // CRITERIA_TYPE_OWN_TOY = 185 uint32 ItemID; - // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING = 38 - // ACHIEVEMENT_CRITERIA_TYPE_REACH_TEAM_RATING = 39 - // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_PERSONAL_RATING = 39 + // CRITERIA_TYPE_HIGHEST_TEAM_RATING = 38 + // CRITERIA_TYPE_REACH_TEAM_RATING = 39 + // CRITERIA_TYPE_HIGHEST_PERSONAL_RATING = 39 uint32 TeamType; - // ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA = 43 + // CRITERIA_TYPE_EXPLORE_AREA = 43 uint32 WorldMapOverlayID; - // ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION = 46 + // CRITERIA_TYPE_GAIN_REPUTATION = 46 uint32 FactionID; - // ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM = 49 + // CRITERIA_TYPE_EQUIP_EPIC_ITEM = 49 uint32 ItemSlot; - // ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT = 50 - // ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT = 51 + // CRITERIA_TYPE_ROLL_NEED_ON_LOOT = 50 + // CRITERIA_TYPE_ROLL_GREED_ON_LOOT = 51 uint32 RollValue; - // ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS = 52 + // CRITERIA_TYPE_HK_CLASS = 52 uint32 ClassID; - // ACHIEVEMENT_CRITERIA_TYPE_HK_RACE = 53 + // CRITERIA_TYPE_HK_RACE = 53 uint32 RaceID; - // ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE = 54 + // CRITERIA_TYPE_DO_EMOTE = 54 uint32 EmoteID; - // ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT = 68 - // ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT = 72 + // CRITERIA_TYPE_USE_GAMEOBJECT = 68 + // CRITERIA_TYPE_FISH_IN_GAMEOBJECT = 72 uint32 GameObjectID; - // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_POWER = 96 + // CRITERIA_TYPE_HIGHEST_POWER = 96 uint32 PowerType; - // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_STAT = 97 + // CRITERIA_TYPE_HIGHEST_STAT = 97 uint32 StatType; - // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_SPELLPOWER = 98 + // CRITERIA_TYPE_HIGHEST_SPELLPOWER = 98 uint32 SpellSchool; - // ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE = 109 + // CRITERIA_TYPE_LOOT_TYPE = 109 uint32 LootType; - // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DUNGEON_ENCOUNTER = 165 + // CRITERIA_TYPE_COMPLETE_DUNGEON_ENCOUNTER = 165 uint32 DungeonEncounterID; - // ACHIEVEMENT_CRITERIA_TYPE_CONSTRUCT_GARRISON_BUILDING = 169 + // CRITERIA_TYPE_CONSTRUCT_GARRISON_BUILDING = 169 uint32 GarrBuildingID; - // ACHIEVEMENT_CRITERIA_TYPE_UPGRADE_GARRISON = 170 + // CRITERIA_TYPE_UPGRADE_GARRISON = 170 uint32 GarrisonLevel; - // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_MISSION = 174 + // CRITERIA_TYPE_COMPLETE_GARRISON_MISSION = 174 uint32 GarrMissionID; - // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_SHIPMENT = 182 + // CRITERIA_TYPE_COMPLETE_GARRISON_SHIPMENT = 182 uint32 CharShipmentContainerID; } Asset; // 2 uint32 StartEvent; // 3 diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index 822415d05ab..327c8cac081 100644 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -91,278 +91,16 @@ enum AchievementFlags ACHIEVEMENT_FLAG_REALM_FIRST_REACH = 0x00000100, // ACHIEVEMENT_FLAG_REALM_FIRST_KILL = 0x00000200, // ACHIEVEMENT_FLAG_UNK3 = 0x00000400, // ACHIEVEMENT_FLAG_HIDE_NAME_IN_TIE - ACHIEVEMENT_FLAG_UNK4 = 0x00000800, // first guild on realm done something + ACHIEVEMENT_FLAG_HIDE_INCOMPLETE = 0x00000800, // hide from UI if not completed ACHIEVEMENT_FLAG_SHOW_IN_GUILD_NEWS = 0x00001000, // Shows in guild news ACHIEVEMENT_FLAG_SHOW_IN_GUILD_HEADER = 0x00002000, // Shows in guild news header ACHIEVEMENT_FLAG_GUILD = 0x00004000, // ACHIEVEMENT_FLAG_SHOW_GUILD_MEMBERS = 0x00008000, // ACHIEVEMENT_FLAG_SHOW_CRITERIA_MEMBERS = 0x00010000, // - ACHIEVEMENT_FLAG_ACCOUNT = 0x00020000 -}; - -enum AchievementCriteriaCondition -{ - ACHIEVEMENT_CRITERIA_CONDITION_NONE = 0, - ACHIEVEMENT_CRITERIA_CONDITION_NO_DEATH = 1, // reset progress on death - ACHIEVEMENT_CRITERIA_CONDITION_UNK2 = 2, // only used in "Complete a daily quest every day for five consecutive days" - ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP = 3, // requires you to be on specific map, reset at change - ACHIEVEMENT_CRITERIA_CONDITION_NO_LOSE = 4, // only used in "Win 10 arenas without losing" - ACHIEVEMENT_CRITERIA_CONDITION_UNK5 = 5, // Have spell? - ACHIEVEMENT_CRITERIA_CONDITION_UNK8 = 8, - ACHIEVEMENT_CRITERIA_CONDITION_NO_SPELL_HIT = 9, // requires the player not to be hit by specific spell - ACHIEVEMENT_CRITERIA_CONDITION_NOT_IN_GROUP = 10, // requires the player not to be in group - ACHIEVEMENT_CRITERIA_CONDITION_UNK13 = 13 // unk -}; - -enum AchievementCriteriaAdditionalCondition -{ - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_DRUNK_VALUE = 1, // NYI - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_UNK2 = 2, - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_ITEM_LEVEL = 3, // NYI - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_CREATURE_ENTRY = 4, - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_PLAYER = 5, - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_DEAD = 6, - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_ENEMY = 7, - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_HAS_AURA = 8, - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_HAS_AURA = 10, - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_HAS_AURA_TYPE = 11, - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_ITEM_QUALITY_MIN = 14, - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_ITEM_QUALITY_EQUALS = 15, - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_UNK16 = 16, - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_AREA_OR_ZONE = 17, - 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, - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_RACE = 25, - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_CLASS = 26, - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_RACE = 27, - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_CLASS = 28, - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_MAX_GROUP_MEMBERS = 29, - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_CREATURE_TYPE = 30, - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_MAP = 32, - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_ITEM_CLASS = 33, // NYI - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_ITEM_SUBCLASS = 34, // NYI - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_COMPLETE_QUEST_NOT_IN_GROUP = 35, // NYI - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_MIN_PERSONAL_RATING = 37, // NYI (when implementing don't forget about ACHIEVEMENT_CRITERIA_CONDITION_NO_LOSE) - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TITLE_BIT_INDEX = 38, - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_LEVEL = 39, - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_LEVEL = 40, - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_ZONE = 41, - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_HEALTH_PERCENT_BELOW = 46, - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_UNK55 = 55, - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_MIN_ACHIEVEMENT_POINTS = 56, // NYI - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_REQUIRES_LFG_GROUP = 58, // NYI - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_UNK60 = 60, - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_REQUIRES_GUILD_GROUP = 61, // NYI - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GUILD_REPUTATION = 62, // NYI - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_RATED_BATTLEGROUND = 63, // NYI - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_PROJECT_RARITY = 65, - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_PROJECT_RACE = 66, - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_BATTLE_PET_SPECIES = 91, - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_QUALITY = 145, - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_LEVEL = 146, - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GARRISON_RARE_MISSION = 147, // NYI - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GARRISON_BUILDING_LEVEL = 149, // NYI - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GARRISON_MISSION_TYPE = 167, // NYI - ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_ILVL = 184, -}; - -enum AchievementCriteriaFlags -{ - ACHIEVEMENT_CRITERIA_FLAG_SHOW_PROGRESS_BAR = 0x00000001, // Show progress as bar - ACHIEVEMENT_CRITERIA_FLAG_HIDDEN = 0x00000002, // Not show criteria in client - ACHIEVEMENT_CRITERIA_FLAG_FAIL_ACHIEVEMENT = 0x00000004, // BG related?? - ACHIEVEMENT_CRITERIA_FLAG_RESET_ON_START = 0x00000008, // - ACHIEVEMENT_CRITERIA_FLAG_IS_DATE = 0x00000010, // not used - ACHIEVEMENT_CRITERIA_FLAG_MONEY_COUNTER = 0x00000020 // Displays counter as money -}; - -enum AchievementCriteriaTimedTypes -{ - ACHIEVEMENT_TIMED_TYPE_EVENT = 1, // Timer is started by internal event with id in timerStartEvent - ACHIEVEMENT_TIMED_TYPE_QUEST = 2, // Timer is started by accepting quest with entry in timerStartEvent - ACHIEVEMENT_TIMED_TYPE_SPELL_CASTER = 5, // Timer is started by casting a spell with entry in timerStartEvent - ACHIEVEMENT_TIMED_TYPE_SPELL_TARGET = 6, // Timer is started by being target of spell with entry in timerStartEvent - 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 -}; - -enum AchievementCriteriaTypes -{ - ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE = 0, - ACHIEVEMENT_CRITERIA_TYPE_WIN_BG = 1, - ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ARCHAEOLOGY_PROJECTS = 3, // struct { uint32 itemCount; } - ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL = 5, - ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL = 7, - ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT = 8, - ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT = 9, - ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY = 10, // you have to complete a daily quest x times in a row - ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE = 11, - ACHIEVEMENT_CRITERIA_TYPE_CURRENCY = 12, - ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE = 13, - ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST = 14, - ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND = 15, - ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP = 16, - ACHIEVEMENT_CRITERIA_TYPE_DEATH = 17, - ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON = 18, - ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID = 19, - ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE = 20, - ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER = 23, - ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING = 24, - ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM = 26, - ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST = 27, - ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET = 28, - ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL = 29, - ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE = 30, - ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA = 31, - ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA = 32, - ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA = 33, - ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL = 34, - ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL = 35, - ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM = 36, - ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA = 37, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING = 38, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_PERSONAL_RATING = 39, - ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL = 40, - ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM = 41, - ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM = 42, - ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA = 43, - ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK = 44, - ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT = 45, - ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION = 46, - ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION = 47, - ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP = 48, - ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM = 49, - ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT = 50, /// @todo itemlevel is mentioned in text but not present in dbc - ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT = 51, - ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS = 52, - ACHIEVEMENT_CRITERIA_TYPE_HK_RACE = 53, - ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE = 54, - ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE = 55, - ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS = 56, /// @todo in some cases map not present, and in some cases need do without die - ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM = 57, - ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS = 59, - ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS = 60, - ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS = 61, - ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD = 62, - ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING = 63, - ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER = 65, - ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL = 66, - ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY = 67, - ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT = 68, - ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2 = 69, - ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL = 70, - ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT = 72, - /// @todo 73: Achievements 1515, 1241, 1103 (Name: Mal'Ganis) - ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN = 74, - ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS = 75, - ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL = 76, - ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL = 77, - ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE = 78, - ACHIEVEMENT_CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS = 80, - ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION = 82, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID = 83, - ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS = 84, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD = 85, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED = 86, - ACHIEVEMENT_CRITERIA_TYPE_GAIN_REVERED_REPUTATION = 87, - ACHIEVEMENT_CRITERIA_TYPE_GAIN_HONORED_REPUTATION = 88, - ACHIEVEMENT_CRITERIA_TYPE_KNOWN_FACTIONS = 89, - ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM = 90, - ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM = 91, - ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED = 93, - ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED = 94, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT = 101, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED = 102, - ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED = 103, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CAST = 104, - ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED = 105, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED = 106, - ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED = 107, - ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN = 108, - ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE = 109, - ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2 = 110, /// @todo target entry is missing - ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE = 112, - ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL = 113, - ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS = 114, - ACHIEVEMENT_CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS = 115, - ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS = 119, - ACHIEVEMENT_CRITERIA_TYPE_SPENT_GOLD_GUILD_REPAIRS = 124, - ACHIEVEMENT_CRITERIA_TYPE_REACH_GUILD_LEVEL = 125, - ACHIEVEMENT_CRITERIA_TYPE_CRAFT_ITEMS_GUILD = 126, - ACHIEVEMENT_CRITERIA_TYPE_CATCH_FROM_POOL = 127, - ACHIEVEMENT_CRITERIA_TYPE_BUY_GUILD_BANK_SLOTS = 128, - ACHIEVEMENT_CRITERIA_TYPE_EARN_GUILD_ACHIEVEMENT_POINTS = 129, - ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_BATTLEGROUND = 130, - ACHIEVEMENT_CRITERIA_TYPE_REACH_BG_RATING = 132, - ACHIEVEMENT_CRITERIA_TYPE_BUY_GUILD_TABARD = 133, - ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_GUILD = 134, - ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILLS_GUILD = 135, - ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE_GUILD = 136, - ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE_TYPE = 138, //struct { Flag flag; uint32 count; } 1: Guild Dungeon, 2:Guild Challenge, 3:Guild battlefield - ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE = 139, //struct { uint32 count; } Guild Challenge - // 140 unk - // 141 unk - // 142 unk - // 143 unk - // 144 unk - ACHIEVEMENT_CRITERIA_TYPE_LFR_DUNGEONS_COMPLETED = 145, - ACHIEVEMENT_CRITERIA_TYPE_LFR_LEAVES = 146, - ACHIEVEMENT_CRITERIA_TYPE_LFR_VOTE_KICKS_INITIATED_BY_PLAYER = 147, - ACHIEVEMENT_CRITERIA_TYPE_LFR_VOTE_KICKS_NOT_INIT_BY_PLAYER = 148, - ACHIEVEMENT_CRITERIA_TYPE_BE_KICKED_FROM_LFR = 149, - ACHIEVEMENT_CRITERIA_TYPE_COUNT_OF_LFR_QUEUE_BOOSTS_BY_TANK = 150, - ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_SCENARIO_COUNT = 151, - ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_SCENARIO = 152, - // ACHIEVEMENT_CRITERIA_TYPE_REACH_SOMETHING_LIKE_AREATRIGGER = 153, - // 154 - ACHIEVEMENT_CRITERIA_TYPE_OWN_BATTLE_PET = 155, - ACHIEVEMENT_CRITERIA_TYPE_OWN_BATTLE_PET_COUNT = 156, - ACHIEVEMENT_CRITERIA_TYPE_CAPTURE_BATTLE_PET = 157, - ACHIEVEMENT_CRITERIA_TYPE_WIN_PET_BATTLE = 158, - // 159 - ACHIEVEMENT_CRITERIA_TYPE_LEVEL_BATTLE_PET = 160, - ACHIEVEMENT_CRITERIA_TYPE_CAPTURE_BATTLE_PET_CREDIT = 161, // triggers a quest credit - ACHIEVEMENT_CRITERIA_TYPE_LEVEL_BATTLE_PET_CREDIT = 162, // triggers a quest credit - ACHIEVEMENT_CRITERIA_TYPE_ENTER_AREA = 163, // triggers a quest credit - ACHIEVEMENT_CRITERIA_TYPE_LEAVE_AREA = 164, // triggers a quest credit - ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DUNGEON_ENCOUNTER = 165, - ACHIEVEMENT_CRITERIA_TYPE_PLACE_GARRISON_BUILDING = 167, - ACHIEVEMENT_CRITERIA_TYPE_UPGRADE_GARRISON_BUILDING = 168, - ACHIEVEMENT_CRITERIA_TYPE_CONSTRUCT_GARRISON_BUILDING = 169, - ACHIEVEMENT_CRITERIA_TYPE_UPGRADE_GARRISON = 170, - ACHIEVEMENT_CRITERIA_TYPE_START_GARRISON_MISSION = 171, - // 172 - ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_MISSION_COUNT = 173, - ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_MISSION = 174, - ACHIEVEMENT_CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER_COUNT = 175, - // 176 - // 177 - ACHIEVEMENT_CRITERIA_TYPE_LEARN_GARRISON_BLUEPRINT_COUNT = 178, - // 179 - // 180 - // 181 - ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_SHIPMENT = 182, - ACHIEVEMENT_CRITERIA_TYPE_RAISE_GARRISON_FOLLOWER_ITEM_LEVEL = 183, - ACHIEVEMENT_CRITERIA_TYPE_RAISE_GARRISON_FOLLOWER_LEVEL = 184, - ACHIEVEMENT_CRITERIA_TYPE_OWN_TOY = 185, - ACHIEVEMENT_CRITERIA_TYPE_OWN_TOY_COUNT = 186, - ACHIEVEMENT_CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER = 187, - ACHIEVEMENT_CRITERIA_TYPE_OWN_HEIRLOOMS = 189 -}; - -#define ACHIEVEMENT_CRITERIA_TYPE_TOTAL 190 - -enum AchievementCriteriaTreeOperator -{ - ACHIEVEMENT_CRITERIA_TREE_OPERATOR_ALL = 4, - ACHIEVEMENT_CRITERIA_TREE_OPERATOR_ANY = 8 + ACHIEVEMENT_FLAG_ACCOUNT = 0x00020000, + ACHIEVEMENT_FLAG_UNK5 = 0x00040000, + ACHIEVEMENT_FLAG_HIDE_ZERO_COUNTER = 0x00080000, // statistic is hidden from UI if no criteria value exists + ACHIEVEMENT_FLAG_TRACKING_FLAG = 0x00100000, // hidden tracking flag, sent to client in all cases except completion announcements }; enum AreaFlags @@ -399,6 +137,271 @@ enum AreaFlags AREA_FLAG_UNK9 = 0x40000000 }; +enum CriteriaCondition +{ + CRITERIA_CONDITION_NONE = 0, + CRITERIA_CONDITION_NO_DEATH = 1, // reset progress on death + CRITERIA_CONDITION_UNK2 = 2, // only used in "Complete a daily quest every day for five consecutive days" + CRITERIA_CONDITION_BG_MAP = 3, // requires you to be on specific map, reset at change + CRITERIA_CONDITION_NO_LOSE = 4, // only used in "Win 10 arenas without losing" + CRITERIA_CONDITION_UNK5 = 5, // Have spell? + CRITERIA_CONDITION_UNK8 = 8, + CRITERIA_CONDITION_NO_SPELL_HIT = 9, // requires the player not to be hit by specific spell + CRITERIA_CONDITION_NOT_IN_GROUP = 10, // requires the player not to be in group + CRITERIA_CONDITION_UNK13 = 13 // unk +}; + +enum CriteriaAdditionalCondition +{ + CRITERIA_ADDITIONAL_CONDITION_SOURCE_DRUNK_VALUE = 1, // NYI + CRITERIA_ADDITIONAL_CONDITION_UNK2 = 2, + CRITERIA_ADDITIONAL_CONDITION_ITEM_LEVEL = 3, // NYI + CRITERIA_ADDITIONAL_CONDITION_TARGET_CREATURE_ENTRY = 4, + CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_PLAYER = 5, + CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_DEAD = 6, + CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_ENEMY = 7, + CRITERIA_ADDITIONAL_CONDITION_SOURCE_HAS_AURA = 8, + CRITERIA_ADDITIONAL_CONDITION_TARGET_HAS_AURA = 10, + CRITERIA_ADDITIONAL_CONDITION_TARGET_HAS_AURA_TYPE = 11, + CRITERIA_ADDITIONAL_CONDITION_ITEM_QUALITY_MIN = 14, + CRITERIA_ADDITIONAL_CONDITION_ITEM_QUALITY_EQUALS = 15, + CRITERIA_ADDITIONAL_CONDITION_UNK16 = 16, + CRITERIA_ADDITIONAL_CONDITION_SOURCE_AREA_OR_ZONE = 17, + CRITERIA_ADDITIONAL_CONDITION_TARGET_AREA_OR_ZONE = 18, + CRITERIA_ADDITIONAL_CONDITION_MAP_DIFFICULTY = 20, + CRITERIA_ADDITIONAL_CONDITION_TARGET_CREATURE_YIELDS_XP = 21, // NYI + CRITERIA_ADDITIONAL_CONDITION_ARENA_TYPE = 24, + CRITERIA_ADDITIONAL_CONDITION_SOURCE_RACE = 25, + CRITERIA_ADDITIONAL_CONDITION_SOURCE_CLASS = 26, + CRITERIA_ADDITIONAL_CONDITION_TARGET_RACE = 27, + CRITERIA_ADDITIONAL_CONDITION_TARGET_CLASS = 28, + CRITERIA_ADDITIONAL_CONDITION_MAX_GROUP_MEMBERS = 29, + CRITERIA_ADDITIONAL_CONDITION_TARGET_CREATURE_TYPE = 30, + CRITERIA_ADDITIONAL_CONDITION_SOURCE_MAP = 32, + CRITERIA_ADDITIONAL_CONDITION_ITEM_CLASS = 33, // NYI + CRITERIA_ADDITIONAL_CONDITION_ITEM_SUBCLASS = 34, // NYI + CRITERIA_ADDITIONAL_CONDITION_COMPLETE_QUEST_NOT_IN_GROUP = 35, // NYI + CRITERIA_ADDITIONAL_CONDITION_MIN_PERSONAL_RATING = 37, // NYI (when implementing don't forget about CRITERIA_CONDITION_NO_LOSE) + CRITERIA_ADDITIONAL_CONDITION_TITLE_BIT_INDEX = 38, + CRITERIA_ADDITIONAL_CONDITION_SOURCE_LEVEL = 39, + CRITERIA_ADDITIONAL_CONDITION_TARGET_LEVEL = 40, + CRITERIA_ADDITIONAL_CONDITION_TARGET_ZONE = 41, + CRITERIA_ADDITIONAL_CONDITION_TARGET_HEALTH_PERCENT_BELOW = 46, + CRITERIA_ADDITIONAL_CONDITION_UNK55 = 55, + CRITERIA_ADDITIONAL_CONDITION_MIN_ACHIEVEMENT_POINTS = 56, // NYI + CRITERIA_ADDITIONAL_CONDITION_REQUIRES_LFG_GROUP = 58, // NYI + CRITERIA_ADDITIONAL_CONDITION_UNK60 = 60, + CRITERIA_ADDITIONAL_CONDITION_REQUIRES_GUILD_GROUP = 61, // NYI + CRITERIA_ADDITIONAL_CONDITION_GUILD_REPUTATION = 62, // NYI + CRITERIA_ADDITIONAL_CONDITION_RATED_BATTLEGROUND = 63, // NYI + CRITERIA_ADDITIONAL_CONDITION_PROJECT_RARITY = 65, + CRITERIA_ADDITIONAL_CONDITION_PROJECT_RACE = 66, + CRITERIA_ADDITIONAL_CONDITION_BATTLE_PET_SPECIES = 91, + CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_QUALITY = 145, + CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_LEVEL = 146, + CRITERIA_ADDITIONAL_CONDITION_GARRISON_RARE_MISSION = 147, // NYI + CRITERIA_ADDITIONAL_CONDITION_GARRISON_BUILDING_LEVEL = 149, // NYI + CRITERIA_ADDITIONAL_CONDITION_GARRISON_MISSION_TYPE = 167, // NYI + CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_ILVL = 184, +}; + +enum CriteriaFlags +{ + CRITERIA_FLAG_SHOW_PROGRESS_BAR = 0x00000001, // Show progress as bar + CRITERIA_FLAG_HIDDEN = 0x00000002, // Not show criteria in client + CRITERIA_FLAG_FAIL_ACHIEVEMENT = 0x00000004, // BG related?? + CRITERIA_FLAG_RESET_ON_START = 0x00000008, // + CRITERIA_FLAG_IS_DATE = 0x00000010, // not used + CRITERIA_FLAG_MONEY_COUNTER = 0x00000020 // Displays counter as money +}; + +enum CriteriaTimedTypes +{ + CRITERIA_TIMED_TYPE_EVENT = 1, // Timer is started by internal event with id in timerStartEvent + CRITERIA_TIMED_TYPE_QUEST = 2, // Timer is started by accepting quest with entry in timerStartEvent + CRITERIA_TIMED_TYPE_SPELL_CASTER = 5, // Timer is started by casting a spell with entry in timerStartEvent + CRITERIA_TIMED_TYPE_SPELL_TARGET = 6, // Timer is started by being target of spell with entry in timerStartEvent + CRITERIA_TIMED_TYPE_CREATURE = 7, // Timer is started by killing creature with entry in timerStartEvent + CRITERIA_TIMED_TYPE_ITEM = 9, // Timer is started by using item with entry in timerStartEvent + CRITERIA_TIMED_TYPE_UNK = 10, // Unknown + CRITERIA_TIMED_TYPE_UNK_2 = 13, // Unknown + CRITERIA_TIMED_TYPE_SCENARIO_STAGE = 14, // Timer is started by changing stages in a scenario + + CRITERIA_TIMED_TYPE_MAX +}; + +enum CriteriaTypes +{ + CRITERIA_TYPE_KILL_CREATURE = 0, + CRITERIA_TYPE_WIN_BG = 1, + CRITERIA_TYPE_COMPLETE_ARCHAEOLOGY_PROJECTS = 3, // struct { uint32 itemCount; } + CRITERIA_TYPE_REACH_LEVEL = 5, + CRITERIA_TYPE_REACH_SKILL_LEVEL = 7, + CRITERIA_TYPE_COMPLETE_ACHIEVEMENT = 8, + CRITERIA_TYPE_COMPLETE_QUEST_COUNT = 9, + CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY = 10, // you have to complete a daily quest x times in a row + CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE = 11, + CRITERIA_TYPE_CURRENCY = 12, + CRITERIA_TYPE_DAMAGE_DONE = 13, + CRITERIA_TYPE_COMPLETE_DAILY_QUEST = 14, + CRITERIA_TYPE_COMPLETE_BATTLEGROUND = 15, + CRITERIA_TYPE_DEATH_AT_MAP = 16, + CRITERIA_TYPE_DEATH = 17, + CRITERIA_TYPE_DEATH_IN_DUNGEON = 18, + CRITERIA_TYPE_COMPLETE_RAID = 19, + CRITERIA_TYPE_KILLED_BY_CREATURE = 20, + CRITERIA_TYPE_KILLED_BY_PLAYER = 23, + CRITERIA_TYPE_FALL_WITHOUT_DYING = 24, + CRITERIA_TYPE_DEATHS_FROM = 26, + CRITERIA_TYPE_COMPLETE_QUEST = 27, + CRITERIA_TYPE_BE_SPELL_TARGET = 28, + CRITERIA_TYPE_CAST_SPELL = 29, + CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE = 30, + CRITERIA_TYPE_HONORABLE_KILL_AT_AREA = 31, + CRITERIA_TYPE_WIN_ARENA = 32, + CRITERIA_TYPE_PLAY_ARENA = 33, + CRITERIA_TYPE_LEARN_SPELL = 34, + CRITERIA_TYPE_HONORABLE_KILL = 35, + CRITERIA_TYPE_OWN_ITEM = 36, + CRITERIA_TYPE_WIN_RATED_ARENA = 37, + CRITERIA_TYPE_HIGHEST_TEAM_RATING = 38, + CRITERIA_TYPE_HIGHEST_PERSONAL_RATING = 39, + CRITERIA_TYPE_LEARN_SKILL_LEVEL = 40, + CRITERIA_TYPE_USE_ITEM = 41, + CRITERIA_TYPE_LOOT_ITEM = 42, + CRITERIA_TYPE_EXPLORE_AREA = 43, + CRITERIA_TYPE_OWN_RANK = 44, + CRITERIA_TYPE_BUY_BANK_SLOT = 45, + CRITERIA_TYPE_GAIN_REPUTATION = 46, + CRITERIA_TYPE_GAIN_EXALTED_REPUTATION = 47, + CRITERIA_TYPE_VISIT_BARBER_SHOP = 48, + CRITERIA_TYPE_EQUIP_EPIC_ITEM = 49, + CRITERIA_TYPE_ROLL_NEED_ON_LOOT = 50, /// @todo itemlevel is mentioned in text but not present in dbc + CRITERIA_TYPE_ROLL_GREED_ON_LOOT = 51, + CRITERIA_TYPE_HK_CLASS = 52, + CRITERIA_TYPE_HK_RACE = 53, + CRITERIA_TYPE_DO_EMOTE = 54, + CRITERIA_TYPE_HEALING_DONE = 55, + CRITERIA_TYPE_GET_KILLING_BLOWS = 56, /// @todo in some cases map not present, and in some cases need do without die + CRITERIA_TYPE_EQUIP_ITEM = 57, + CRITERIA_TYPE_MONEY_FROM_VENDORS = 59, + CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS = 60, + CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS = 61, + CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD = 62, + CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING = 63, + CRITERIA_TYPE_GOLD_SPENT_AT_BARBER = 65, + CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL = 66, + CRITERIA_TYPE_LOOT_MONEY = 67, + CRITERIA_TYPE_USE_GAMEOBJECT = 68, + CRITERIA_TYPE_BE_SPELL_TARGET2 = 69, + CRITERIA_TYPE_SPECIAL_PVP_KILL = 70, + CRITERIA_TYPE_FISH_IN_GAMEOBJECT = 72, + /// @todo 73: Achievements 1515, 1241, 1103 (Name: Mal'Ganis) + CRITERIA_TYPE_ON_LOGIN = 74, + CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS = 75, + CRITERIA_TYPE_WIN_DUEL = 76, + CRITERIA_TYPE_LOSE_DUEL = 77, + CRITERIA_TYPE_KILL_CREATURE_TYPE = 78, + CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS = 80, + CRITERIA_TYPE_CREATE_AUCTION = 82, + CRITERIA_TYPE_HIGHEST_AUCTION_BID = 83, + CRITERIA_TYPE_WON_AUCTIONS = 84, + CRITERIA_TYPE_HIGHEST_AUCTION_SOLD = 85, + CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED = 86, + CRITERIA_TYPE_GAIN_REVERED_REPUTATION = 87, + CRITERIA_TYPE_GAIN_HONORED_REPUTATION = 88, + CRITERIA_TYPE_KNOWN_FACTIONS = 89, + CRITERIA_TYPE_LOOT_EPIC_ITEM = 90, + CRITERIA_TYPE_RECEIVE_EPIC_ITEM = 91, + CRITERIA_TYPE_ROLL_NEED = 93, + CRITERIA_TYPE_ROLL_GREED = 94, + CRITERIA_TYPE_HIGHEST_HIT_DEALT = 101, + CRITERIA_TYPE_HIGHEST_HIT_RECEIVED = 102, + CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED = 103, + CRITERIA_TYPE_HIGHEST_HEAL_CAST = 104, + CRITERIA_TYPE_TOTAL_HEALING_RECEIVED = 105, + CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED = 106, + CRITERIA_TYPE_QUEST_ABANDONED = 107, + CRITERIA_TYPE_FLIGHT_PATHS_TAKEN = 108, + CRITERIA_TYPE_LOOT_TYPE = 109, + CRITERIA_TYPE_CAST_SPELL2 = 110, /// @todo target entry is missing + CRITERIA_TYPE_LEARN_SKILL_LINE = 112, + CRITERIA_TYPE_EARN_HONORABLE_KILL = 113, + CRITERIA_TYPE_ACCEPTED_SUMMONINGS = 114, + CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS = 115, + CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS = 119, + CRITERIA_TYPE_SPENT_GOLD_GUILD_REPAIRS = 124, + CRITERIA_TYPE_REACH_GUILD_LEVEL = 125, + CRITERIA_TYPE_CRAFT_ITEMS_GUILD = 126, + CRITERIA_TYPE_CATCH_FROM_POOL = 127, + CRITERIA_TYPE_BUY_GUILD_BANK_SLOTS = 128, + CRITERIA_TYPE_EARN_GUILD_ACHIEVEMENT_POINTS = 129, + CRITERIA_TYPE_WIN_RATED_BATTLEGROUND = 130, + CRITERIA_TYPE_REACH_BG_RATING = 132, + CRITERIA_TYPE_BUY_GUILD_TABARD = 133, + CRITERIA_TYPE_COMPLETE_QUESTS_GUILD = 134, + CRITERIA_TYPE_HONORABLE_KILLS_GUILD = 135, + CRITERIA_TYPE_KILL_CREATURE_TYPE_GUILD = 136, + CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE_TYPE = 138, //struct { Flag flag; uint32 count; } 1: Guild Dungeon, 2:Guild Challenge, 3:Guild battlefield + CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE = 139, //struct { uint32 count; } Guild Challenge + // 140 unk + // 141 unk + // 142 unk + // 143 unk + // 144 unk + CRITERIA_TYPE_LFR_DUNGEONS_COMPLETED = 145, + CRITERIA_TYPE_LFR_LEAVES = 146, + CRITERIA_TYPE_LFR_VOTE_KICKS_INITIATED_BY_PLAYER = 147, + CRITERIA_TYPE_LFR_VOTE_KICKS_NOT_INIT_BY_PLAYER = 148, + CRITERIA_TYPE_BE_KICKED_FROM_LFR = 149, + CRITERIA_TYPE_COUNT_OF_LFR_QUEUE_BOOSTS_BY_TANK = 150, + CRITERIA_TYPE_COMPLETE_SCENARIO_COUNT = 151, + CRITERIA_TYPE_COMPLETE_SCENARIO = 152, + // CRITERIA_TYPE_REACH_SOMETHING_LIKE_AREATRIGGER = 153, + // 154 + CRITERIA_TYPE_OWN_BATTLE_PET = 155, + CRITERIA_TYPE_OWN_BATTLE_PET_COUNT = 156, + CRITERIA_TYPE_CAPTURE_BATTLE_PET = 157, + CRITERIA_TYPE_WIN_PET_BATTLE = 158, + // 159 + CRITERIA_TYPE_LEVEL_BATTLE_PET = 160, + CRITERIA_TYPE_CAPTURE_BATTLE_PET_CREDIT = 161, // triggers a quest credit + CRITERIA_TYPE_LEVEL_BATTLE_PET_CREDIT = 162, // triggers a quest credit + CRITERIA_TYPE_ENTER_AREA = 163, // triggers a quest credit + CRITERIA_TYPE_LEAVE_AREA = 164, // triggers a quest credit + CRITERIA_TYPE_COMPLETE_DUNGEON_ENCOUNTER = 165, + CRITERIA_TYPE_PLACE_GARRISON_BUILDING = 167, + CRITERIA_TYPE_UPGRADE_GARRISON_BUILDING = 168, + CRITERIA_TYPE_CONSTRUCT_GARRISON_BUILDING = 169, + CRITERIA_TYPE_UPGRADE_GARRISON = 170, + CRITERIA_TYPE_START_GARRISON_MISSION = 171, + // 172 + CRITERIA_TYPE_COMPLETE_GARRISON_MISSION_COUNT = 173, + CRITERIA_TYPE_COMPLETE_GARRISON_MISSION = 174, + CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER_COUNT = 175, + // 176 + // 177 + CRITERIA_TYPE_LEARN_GARRISON_BLUEPRINT_COUNT = 178, + // 179 + // 180 + // 181 + CRITERIA_TYPE_COMPLETE_GARRISON_SHIPMENT = 182, + CRITERIA_TYPE_RAISE_GARRISON_FOLLOWER_ITEM_LEVEL = 183, + CRITERIA_TYPE_RAISE_GARRISON_FOLLOWER_LEVEL = 184, + CRITERIA_TYPE_OWN_TOY = 185, + CRITERIA_TYPE_OWN_TOY_COUNT = 186, + CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER = 187, + CRITERIA_TYPE_OWN_HEIRLOOMS = 189 +}; + +#define CRITERIA_TYPE_TOTAL 190 + +enum CriteriaTreeOperator +{ + CRITERIA_TREE_OPERATOR_ALL = 4, + CRITERIA_TREE_OPERATOR_ANY = 8 +}; + enum Difficulty : uint8 { DIFFICULTY_NONE = 0, diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp index 25732e32f93..94885deeffe 100644 --- a/src/server/game/DungeonFinding/LFGMgr.cpp +++ b/src/server/game/DungeonFinding/LFGMgr.cpp @@ -1410,7 +1410,7 @@ void LFGMgr::FinishDungeon(ObjectGuid gguid, const uint32 dungeonId) // Update achievements if (dungeon->difficulty == DIFFICULTY_HEROIC) - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS, 1); + player->UpdateCriteria(CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS, 1); LfgReward const* reward = GetRandomDungeonReward(rDungeonId, player->getLevel()); if (!reward) diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 06851b938ff..42d7ff404db 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -1736,7 +1736,7 @@ void GameObject::Use(Unit* user) Player* player = user->ToPlayer(); player->SendLoot(GetGUID(), LOOT_FISHINGHOLE); - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT, GetGOInfo()->entry); + player->UpdateCriteria(CRITERIA_TYPE_FISH_IN_GAMEOBJECT, GetGOInfo()->entry); return; } diff --git a/src/server/game/Entities/Player/KillRewarder.cpp b/src/server/game/Entities/Player/KillRewarder.cpp index d7ebf9cc220..3c022538fe2 100644 --- a/src/server/game/Entities/Player/KillRewarder.cpp +++ b/src/server/game/Entities/Player/KillRewarder.cpp @@ -177,7 +177,7 @@ inline void KillRewarder::_RewardKillCredit(Player* player) if (Creature* target = _victim->ToCreature()) { player->KilledMonster(target->GetCreatureTemplate(), target->GetGUID()); - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE, target->GetCreatureType(), 1, 0, target); + player->UpdateCriteria(CRITERIA_TYPE_KILL_CREATURE_TYPE, target->GetCreatureType(), 1, 0, target); } } @@ -240,7 +240,7 @@ void KillRewarder::_RewardGroup() if (member->IsAtGroupRewardDistance(_victim)) { _RewardPlayer(member, isDungeon); - member->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL, 1, 0, 0, _victim); + member->UpdateCriteria(CRITERIA_TYPE_SPECIAL_PVP_KILL, 1, 0, 0, _victim); } } } @@ -277,7 +277,7 @@ void KillRewarder::Reward() if (ObjectGuid::LowType guildId = victim->GetMap()->GetOwnerGuildId()) if (Guild* guild = sGuildMgr->GetGuildById(guildId)) - guild->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, victim->GetEntry(), 1, 0, victim, _killer); + guild->UpdateCriteria(CRITERIA_TYPE_KILL_CREATURE, victim->GetEntry(), 1, 0, victim, _killer); } } diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index f722319e192..d32150b8038 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -332,7 +332,7 @@ Player::Player(WorldSession* session) : Unit(true) memset(_voidStorageItems, 0, VOID_STORAGE_MAX_SLOT * sizeof(VoidStorageItem*)); - m_achievementMgr = new AchievementMgr<Player>(this); + m_achievementMgr = new PlayerAchievementMgr(this); m_reputationMgr = new ReputationMgr(this); for (uint8 i = 0; i < MAX_CUF_PROFILES; ++i) @@ -770,7 +770,7 @@ uint32 Player::EnvironmentalDamage(EnviromentalDamage type, uint32 damage) SendDurabilityLoss(this, 10); } - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM, 1, type); + UpdateCriteria(CRITERIA_TYPE_DEATHS_FROM, 1, type); } return final_damage; @@ -1088,7 +1088,7 @@ void Player::Update(uint32 p_time) } } - m_achievementMgr->UpdateTimedAchievements(p_time); + m_achievementMgr->UpdateTimedCriteria(p_time); if (HasUnitState(UNIT_STATE_MELEE_ATTACKING) && !HasUnitState(UNIT_STATE_CASTING)) { @@ -1373,12 +1373,12 @@ void Player::setDeathState(DeathState s) // passive spell if (!ressSpellId) ressSpellId = GetResurrectionSpellId(); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP, 1); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATH, 1); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON, 1); - ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, ACHIEVEMENT_CRITERIA_CONDITION_NO_DEATH); - ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL, ACHIEVEMENT_CRITERIA_CONDITION_NO_DEATH); - ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS, ACHIEVEMENT_CRITERIA_CONDITION_NO_DEATH); + UpdateCriteria(CRITERIA_TYPE_DEATH_AT_MAP, 1); + UpdateCriteria(CRITERIA_TYPE_DEATH, 1); + UpdateCriteria(CRITERIA_TYPE_DEATH_IN_DUNGEON, 1); + ResetCriteria(CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, CRITERIA_CONDITION_NO_DEATH); + ResetCriteria(CRITERIA_TYPE_HONORABLE_KILL, CRITERIA_CONDITION_NO_DEATH); + ResetCriteria(CRITERIA_TYPE_GET_KILLING_BLOWS, CRITERIA_CONDITION_NO_DEATH); } Unit::setDeathState(s); @@ -2475,7 +2475,7 @@ void Player::GiveLevel(uint8 level) CharacterDatabase.CommitTransaction(trans); } - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL); + UpdateCriteria(CRITERIA_TYPE_REACH_LEVEL); // Refer-A-Friend if (GetSession()->GetRecruiterId()) @@ -3173,11 +3173,11 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent // not ranked skills for (SkillLineAbilityMap::const_iterator _spell_idx = skill_bounds.first; _spell_idx != skill_bounds.second; ++_spell_idx) { - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE, _spell_idx->second->SkillLine); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS, _spell_idx->second->SkillLine); + UpdateCriteria(CRITERIA_TYPE_LEARN_SKILL_LINE, _spell_idx->second->SkillLine); + UpdateCriteria(CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS, _spell_idx->second->SkillLine); } - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL, spellId); + UpdateCriteria(CRITERIA_TYPE_LEARN_SPELL, spellId); } // return true (for send learn packet) only if spell active (in case ranked spells) and not replace old spell @@ -3535,8 +3535,8 @@ bool Player::ResetTalents(bool noCost) if (!noCost) { ModifyMoney(-(int64)cost); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS, cost); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS, 1); + UpdateCriteria(CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS, cost); + UpdateCriteria(CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS, 1); SetTalentResetCost(cost); SetTalentResetTime(time(nullptr)); @@ -5137,7 +5137,7 @@ bool Player::UpdateSkill(uint32 skill_id, uint32 step) itr->second.uState = SKILL_CHANGED; UpdateSkillEnchantments(skill_id, value, new_value); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL, skill_id); + UpdateCriteria(CRITERIA_TYPE_REACH_SKILL_LEVEL, skill_id); return true; } @@ -5289,7 +5289,7 @@ bool Player::UpdateSkillPro(uint16 skillId, int32 chance, uint32 step) } UpdateSkillEnchantments(skillId, value, new_value); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL, skillId); + UpdateCriteria(CRITERIA_TYPE_REACH_SKILL_LEVEL, skillId); TC_LOG_DEBUG("entities.player.skills", "Player::UpdateSkillPro: Player '%s' (%s), SkillID: %u, Chance: %3.1f%% taken", GetName().c_str(), GetGUID().ToString().c_str(), skillId, chance / 10.0f); return true; @@ -5417,8 +5417,8 @@ void Player::SetSkill(uint16 id, uint16 step, uint16 newVal, uint16 maxVal) if (newVal > currVal) UpdateSkillEnchantments(id, currVal, newVal); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL, id); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL, id); + UpdateCriteria(CRITERIA_TYPE_REACH_SKILL_LEVEL, id); + UpdateCriteria(CRITERIA_TYPE_LEARN_SKILL_LEVEL, id); } else //remove { @@ -5483,8 +5483,8 @@ void Player::SetSkill(uint16 id, uint16 step, uint16 newVal, uint16 maxVal) SetUInt16Value(PLAYER_SKILL_LINEID + SKILL_MAX_RANK_OFFSET + field, offset, maxVal); UpdateSkillEnchantments(id, currVal, newVal); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL, id); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL, id); + UpdateCriteria(CRITERIA_TYPE_REACH_SKILL_LEVEL, id); + UpdateCriteria(CRITERIA_TYPE_LEARN_SKILL_LEVEL, id); // insert new entry or update if not deleted old entry yet if (itr != mSkillStatus.end()) @@ -5896,7 +5896,7 @@ void Player::CheckAreaExploreAndOutdoor() { SetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset, (uint32)(currFields | val)); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA); + UpdateCriteria(CRITERIA_TYPE_EXPLORE_AREA); if (areaEntry->ExplorationLevel > 0) { @@ -6256,11 +6256,11 @@ bool Player::RewardHonor(Unit* victim, uint32 groupsize, int32 honor, bool pvpto ApplyModUInt16Value(PLAYER_FIELD_KILLS, PLAYER_FIELD_KILLS_OFFSET_TODAY_KILLS, 1, true); // and those in a lifetime ApplyModUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS, 1, true); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS, victim->getClass()); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HK_RACE, victim->getRace()); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA, GetAreaId()); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL, 1, 0, 0, victim); + UpdateCriteria(CRITERIA_TYPE_EARN_HONORABLE_KILL); + UpdateCriteria(CRITERIA_TYPE_HK_CLASS, victim->getClass()); + UpdateCriteria(CRITERIA_TYPE_HK_RACE, victim->getRace()); + UpdateCriteria(CRITERIA_TYPE_HONORABLE_KILL_AT_AREA, GetAreaId()); + UpdateCriteria(CRITERIA_TYPE_HONORABLE_KILL, 1, 0, 0, victim); } else { @@ -6568,7 +6568,7 @@ void Player::ModifyCurrency(uint32 id, int32 count, bool printLog/* = true*/, bo itr->second.TrackedQuantity = newTrackedCount; if (count > 0) - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CURRENCY, id, count); + UpdateCriteria(CRITERIA_TYPE_CURRENCY, id, count); CurrencyChanged(id, count); @@ -7040,8 +7040,8 @@ void Player::DuelComplete(DuelCompleteType type) } break; case DUEL_WON: - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL, 1); - duel->opponent->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL, 1); + UpdateCriteria(CRITERIA_TYPE_LOSE_DUEL, 1); + duel->opponent->UpdateCriteria(CRITERIA_TYPE_WIN_DUEL, 1); // Credit for quest Death's Challenge if (getClass() == CLASS_DEATH_KNIGHT && duel->opponent->GetQuestStatus(12733) == QUEST_STATUS_INCOMPLETE) @@ -11031,8 +11031,8 @@ Item* Player::StoreNewItem(ItemPosCountVec const& pos, uint32 itemId, bool updat if (item) { ItemAddedQuestCheck(itemId, count); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM, itemId, count); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM, itemId, 1); + UpdateCriteria(CRITERIA_TYPE_RECEIVE_EPIC_ITEM, itemId, count); + UpdateCriteria(CRITERIA_TYPE_OWN_ITEM, itemId, 1); if (sDB2Manager.GetHeirloomByItemId(itemId)) GetSession()->GetCollectionMgr()->AddHeirloom(itemId, 0); @@ -11206,7 +11206,7 @@ Item* Player::EquipNewItem(uint16 pos, uint32 item, bool update) if (Item* pItem = Item::CreateItem(item, 1, this)) { ItemAddedQuestCheck(item, 1); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM, item, 1); + UpdateCriteria(CRITERIA_TYPE_RECEIVE_EPIC_ITEM, item, 1); return EquipItem(pos, pItem, update); } @@ -11315,8 +11315,8 @@ Item* Player::EquipItem(uint16 pos, Item* pItem, bool update) } // only for full equip instead adding to stack - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM, pItem->GetEntry()); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM, pItem->GetEntry(), slot); + UpdateCriteria(CRITERIA_TYPE_EQUIP_ITEM, pItem->GetEntry()); + UpdateCriteria(CRITERIA_TYPE_EQUIP_EPIC_ITEM, pItem->GetEntry(), slot); return pItem; } @@ -11337,8 +11337,8 @@ void Player::QuickEquipItem(uint16 pos, Item* pItem) pItem->SendUpdateToPlayer(this); } - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM, pItem->GetEntry()); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM, pItem->GetEntry(), slot); + UpdateCriteria(CRITERIA_TYPE_EQUIP_ITEM, pItem->GetEntry()); + UpdateCriteria(CRITERIA_TYPE_EQUIP_EPIC_ITEM, pItem->GetEntry(), slot); } } @@ -11490,7 +11490,7 @@ void Player::MoveItemToInventory(ItemPosCountVec const& dest, Item* pItem, bool { // update quest counters ItemAddedQuestCheck(pItem->GetEntry(), pItem->GetCount()); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM, pItem->GetEntry(), pItem->GetCount()); + UpdateCriteria(CRITERIA_TYPE_RECEIVE_EPIC_ITEM, pItem->GetEntry(), pItem->GetCount()); // store item Item* pLastItem = StoreItem(dest, pItem, update); @@ -14099,7 +14099,7 @@ void Player::AddQuest(Quest const* quest, Object* questGiver) m_QuestStatusSave[quest_id] = QUEST_DEFAULT_SAVE_TYPE; - StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_QUEST, quest_id); + StartCriteriaTimer(CRITERIA_TIMED_TYPE_QUEST, quest_id); SendQuestUpdate(quest_id); @@ -14307,7 +14307,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, ModifyMoney(moneyRew); if (moneyRew > 0) - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD, uint32(moneyRew)); + UpdateCriteria(CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD, uint32(moneyRew)); } // honor reward @@ -14335,8 +14335,8 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, SetDailyQuestStatus(quest_id); if (quest->IsDaily()) { - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST, quest_id); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY, quest_id); + UpdateCriteria(CRITERIA_TYPE_COMPLETE_DAILY_QUEST, quest_id); + UpdateCriteria(CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY, quest_id); } } else if (quest->IsWeekly()) @@ -14383,9 +14383,9 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, } if (quest->GetZoneOrSort() > 0) - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE, quest->GetZoneOrSort()); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST, quest->GetQuestId()); + UpdateCriteria(CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE, quest->GetZoneOrSort()); + UpdateCriteria(CRITERIA_TYPE_COMPLETE_QUEST_COUNT); + UpdateCriteria(CRITERIA_TYPE_COMPLETE_QUEST, quest->GetQuestId()); if (uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(quest_id)) SetQuestCompletedBit(questBit, true); @@ -15453,8 +15453,8 @@ void Player::KilledMonsterCredit(uint32 entry, ObjectGuid guid /*= ObjectGuid::E real_entry = killed->GetEntry(); } - StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_CREATURE, real_entry); // MUST BE CALLED FIRST - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, real_entry, addKillCount, 0, killed); + StartCriteriaTimer(CRITERIA_TIMED_TYPE_CREATURE, real_entry); // MUST BE CALLED FIRST + UpdateCriteria(CRITERIA_TYPE_KILL_CREATURE, real_entry, addKillCount, 0, killed); for (uint8 i = 0; i < MAX_QUEST_LOG_SIZE; ++i) { @@ -16321,7 +16321,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) SetObjectScale(1.0f); SetFloatValue(UNIT_FIELD_HOVERHEIGHT, 1.0f); - // load achievements before anything else to prevent multiple gains for the same achievement/criteria on every loading (as loading does call UpdateAchievementCriteria) + // load achievements before anything else to prevent multiple gains for the same achievement/criteria on every loading (as loading does call UpdateCriteria) m_achievementMgr->LoadFromDB(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ACHIEVEMENTS), holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_CRITERIA_PROGRESS)); uint64 money = fields[8].GetUInt64(); @@ -20794,7 +20794,7 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc } //Checks and preparations done, DO FLIGHT - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN, 1); + UpdateCriteria(CRITERIA_TYPE_FLIGHT_PATHS_TAKEN, 1); // prevent stealth flight //RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TALK); @@ -20805,14 +20805,14 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc ASSERT(lastPathNode); m_taxi.ClearTaxiDestinations(); ModifyMoney(-int64(totalcost)); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING, totalcost); + UpdateCriteria(CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING, totalcost); TeleportTo(lastPathNode->MapID, lastPathNode->Pos.X, lastPathNode->Pos.Y, lastPathNode->Pos.Z, GetOrientation()); return false; } else { ModifyMoney(-int64(firstcost)); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING, firstcost); + UpdateCriteria(CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING, firstcost); GetSession()->SendActivateTaxiReply(ERR_TAXIOK); GetSession()->SendDoFlight(mount_display_id, sourcepath); } @@ -22153,7 +22153,7 @@ void Player::SetMoney(uint64 value) { SetUInt64Value(PLAYER_FIELD_COINAGE, value); MoneyChanged(value); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED); + UpdateCriteria(CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED); } bool Player::IsQuestRewarded(uint32 quest_id) const @@ -22277,7 +22277,7 @@ void Player::SendInitialPacketsBeforeAddToMap() /// SMSG_EQUIPMENT_SET_LIST SendEquipmentSetList(); - m_achievementMgr->SendAllAchievementData(this); + m_achievementMgr->SendAllData(this); /// SMSG_LOGIN_SETTIMESPEED static float const TimeSpeed = 0.01666667f; @@ -23165,7 +23165,7 @@ void Player::SummonIfPossible(bool agree) m_summon_expire = 0; - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS, 1); + UpdateCriteria(CRITERIA_TYPE_ACCEPTED_SUMMONINGS, 1); TeleportTo(m_summon_location); } @@ -24365,9 +24365,9 @@ void Player::StoreLootItem(uint8 lootSlot, Loot* loot) guild->AddGuildNews(GUILD_NEWS_ITEM_LOOTED, GetGUID(), 0, item->itemid); SendNewItem(newitem, uint32(item->count), false, false, true); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, item->itemid, item->count); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE, item->itemid, item->count, loot->loot_type); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM, item->itemid, item->count); + UpdateCriteria(CRITERIA_TYPE_LOOT_ITEM, item->itemid, item->count); + UpdateCriteria(CRITERIA_TYPE_LOOT_TYPE, item->itemid, item->count, loot->loot_type); + UpdateCriteria(CRITERIA_TYPE_LOOT_EPIC_ITEM, item->itemid, item->count); // LootItem is being removed (looted) from the container, delete it from the DB. if (!loot->containerID.IsEmpty()) @@ -24623,7 +24623,7 @@ void Player::HandleFall(MovementInfo const& movementInfo) // recheck alive, might have died of EnvironmentalDamage, avoid cases when player die in fact like Spirit of Redemption case if (IsAlive() && final_damage < original_health) - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING, uint32(z_diff*100)); + UpdateCriteria(CRITERIA_TYPE_FALL_WITHOUT_DYING, uint32(z_diff*100)); } //Z given by moveinfo, LastZ, FallTime, WaterZ, MapZ, Damage, Safefall reduction @@ -24653,34 +24653,34 @@ bool Player::HasAchieved(uint32 achievementId) const return m_achievementMgr->HasAchieved(achievementId); } -void Player::StartTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry, uint32 timeLost/* = 0*/) +void Player::StartCriteriaTimer(CriteriaTimedTypes type, uint32 entry, uint32 timeLost/* = 0*/) { - m_achievementMgr->StartTimedAchievement(type, entry, timeLost); + m_achievementMgr->StartCriteriaTimer(type, entry, timeLost); } -void Player::RemoveTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry) +void Player::RemoveCriteriaTimer(CriteriaTimedTypes type, uint32 entry) { - m_achievementMgr->RemoveTimedAchievement(type, entry); + m_achievementMgr->RemoveCriteriaTimer(type, entry); } -void Player::ResetAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1 /*= 0*/, uint64 miscValue2 /*= 0*/, bool evenIfCriteriaComplete /* = false*/) +void Player::ResetCriteria(CriteriaTypes type, uint64 miscValue1 /*= 0*/, uint64 miscValue2 /*= 0*/, bool evenIfCriteriaComplete /* = false*/) { - m_achievementMgr->ResetAchievementCriteria(type, miscValue1, miscValue2, evenIfCriteriaComplete); + m_achievementMgr->ResetCriteria(type, miscValue1, miscValue2, evenIfCriteriaComplete); } -void Player::UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1 /*= 0*/, uint64 miscValue2 /*= 0*/, uint64 miscValue3 /*= 0*/, Unit* unit /*= NULL*/) +void Player::UpdateCriteria(CriteriaTypes type, uint64 miscValue1 /*= 0*/, uint64 miscValue2 /*= 0*/, uint64 miscValue3 /*= 0*/, Unit* unit /*= NULL*/) { - m_achievementMgr->UpdateAchievementCriteria(type, miscValue1, miscValue2, miscValue3, unit, this); + m_achievementMgr->UpdateCriteria(type, miscValue1, miscValue2, miscValue3, unit, this); Guild* guild = sGuildMgr->GetGuildById(GetGuildId()); if (!guild) return; // Update only individual achievement criteria here, otherwise we may get multiple updates // from a single boss kill - if (sAchievementMgr->IsGroupCriteriaType(type)) + if (CriteriaMgr::IsGroupCriteriaType(type)) return; - guild->UpdateAchievementCriteria(type, miscValue1, miscValue2, miscValue3, unit, this); + guild->UpdateCriteria(type, miscValue1, miscValue2, miscValue3, unit, this); } void Player::CompletedAchievement(AchievementEntry const* entry) diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 7128a6feaa8..a2a7c7794cd 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -40,7 +40,7 @@ struct ItemExtendedCostEntry; struct TrainerSpell; struct VendorItem; -template<class T> class AchievementMgr; +class PlayerAchievementMgr; class ReputationMgr; class Channel; class Creature; @@ -2429,10 +2429,10 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> uint32 GetAchievementPoints() const; bool HasAchieved(uint32 achievementId) const; void ResetAchievements(); - void ResetAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1 = 0, uint64 miscValue2 = 0, bool evenIfCriteriaComplete = false); - void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1 = 0, uint64 miscValue2 = 0, uint64 miscValue3 = 0, Unit* unit = NULL); - void StartTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry, uint32 timeLost = 0); - void RemoveTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry); + void ResetCriteria(CriteriaTypes type, uint64 miscValue1 = 0, uint64 miscValue2 = 0, bool evenIfCriteriaComplete = false); + void UpdateCriteria(CriteriaTypes type, uint64 miscValue1 = 0, uint64 miscValue2 = 0, uint64 miscValue3 = 0, Unit* unit = NULL); + void StartCriteriaTimer(CriteriaTimedTypes type, uint32 entry, uint32 timeLost = 0); + void RemoveCriteriaTimer(CriteriaTimedTypes type, uint32 entry); void CompletedAchievement(AchievementEntry const* entry); bool HasTitle(uint32 bitIndex) const; @@ -2813,7 +2813,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> uint32 m_temporaryUnsummonedPetNumber; uint32 m_oldpetspell; - AchievementMgr<Player>* m_achievementMgr; + PlayerAchievementMgr* m_achievementMgr; ReputationMgr* m_reputationMgr; uint32 m_ChampioningFaction; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 4f15ed1d078..589bde335f0 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -740,12 +740,12 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam if (Battleground* bg = killer->GetBattleground()) bg->UpdatePlayerScore(killer, SCORE_DAMAGE_DONE, damage); - killer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE, damage, 0, 0, victim); - killer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT, damage); + killer->UpdateCriteria(CRITERIA_TYPE_DAMAGE_DONE, damage, 0, 0, victim); + killer->UpdateCriteria(CRITERIA_TYPE_HIGHEST_HIT_DEALT, damage); } if (victim->GetTypeId() == TYPEID_PLAYER) - victim->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED, damage); + victim->ToPlayer()->UpdateCriteria(CRITERIA_TYPE_HIGHEST_HIT_RECEIVED, damage); else if (!victim->IsControlledByPlayer() || victim->IsVehicle()) { if (!victim->ToCreature()->hasLootRecipient()) @@ -760,7 +760,7 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam TC_LOG_DEBUG("entities.unit", "DealDamage: victim just died"); if (victim->GetTypeId() == TYPEID_PLAYER && victim != this) - victim->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED, health); + victim->ToPlayer()->UpdateCriteria(CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED, health); Kill(victim, durabilityLoss); } @@ -769,7 +769,7 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam TC_LOG_DEBUG("entities.unit", "DealDamageAlive"); if (victim->GetTypeId() == TYPEID_PLAYER) - victim->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED, damage); + victim->ToPlayer()->UpdateCriteria(CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED, damage); victim->ModifyHealth(-(int32)damage); @@ -7585,15 +7585,15 @@ int32 Unit::DealHeal(Unit* victim, uint32 addhealth) // use the actual gain, as the overheal shall not be counted, skip gain 0 (it ignored anyway in to criteria) if (gain) - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE, gain, 0, 0, victim); + player->UpdateCriteria(CRITERIA_TYPE_HEALING_DONE, gain, 0, 0, victim); - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CAST, addhealth); + player->UpdateCriteria(CRITERIA_TYPE_HIGHEST_HEAL_CAST, addhealth); } if (Player* player = victim->ToPlayer()) { - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED, gain); - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED, addhealth); + player->UpdateCriteria(CRITERIA_TYPE_TOTAL_HEALING_RECEIVED, gain); + player->UpdateCriteria(CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED, addhealth); } return gain; @@ -13165,7 +13165,7 @@ void Unit::Kill(Unit* victim, bool durabilityLoss) // update get killing blow achievements, must be done before setDeathState to be able to require auras on target // and before Spirit of Redemption as it also removes auras if (Player* killerPlayer = GetCharmerOrOwnerPlayerOrPlayerItself()) - killerPlayer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS, 1, 0, 0, victim); + killerPlayer->UpdateCriteria(CRITERIA_TYPE_GET_KILLING_BLOWS, 1, 0, 0, victim); // if talent known but not triggered (check priest class for speedup check) bool spiritOfRedemption = false; @@ -13334,9 +13334,9 @@ void Unit::Kill(Unit* victim, bool durabilityLoss) if (victim->GetTypeId() == TYPEID_PLAYER) { if (GetTypeId() == TYPEID_UNIT) - victim->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE, GetEntry()); + victim->ToPlayer()->UpdateCriteria(CRITERIA_TYPE_KILLED_BY_CREATURE, GetEntry()); else if (GetTypeId() == TYPEID_PLAYER && victim != this) - victim->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER, 1, ToPlayer()->GetTeam()); + victim->ToPlayer()->UpdateCriteria(CRITERIA_TYPE_KILLED_BY_PLAYER, 1, ToPlayer()->GetTeam()); } // Hook for OnPVPKill Event diff --git a/src/server/game/Garrison/Garrison.cpp b/src/server/game/Garrison/Garrison.cpp index cc07187d7a9..56cbb9ad58e 100644 --- a/src/server/game/Garrison/Garrison.cpp +++ b/src/server/game/Garrison/Garrison.cpp @@ -407,7 +407,7 @@ void Garrison::PlaceBuilding(uint32 garrPlotInstanceId, uint32 garrBuildingId) _owner->SendDirectMessage(buildingRemoved.Write()); } - _owner->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_PLACE_GARRISON_BUILDING, garrBuildingId); + _owner->UpdateCriteria(CRITERIA_TYPE_PLACE_GARRISON_BUILDING, garrBuildingId); } _owner->SendDirectMessage(placeBuildingResult.Write()); @@ -511,7 +511,7 @@ void Garrison::AddFollower(uint32 garrFollowerId) addFollowerResult.Follower = follower.PacketInfo; _owner->SendDirectMessage(addFollowerResult.Write()); - _owner->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER, follower.PacketInfo.DbID); + _owner->UpdateCriteria(CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER, follower.PacketInfo.DbID); } Garrison::Follower const* Garrison::GetFollower(uint64 dbId) const diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 8b12f60cbb8..96936a82d08 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -6289,7 +6289,7 @@ void ObjectMgr::LoadAccessRequirements() if (ar->achievement) { - if (!sAchievementMgr->GetAchievement(ar->achievement)) + if (!sAchievementStore.LookupEntry(ar->achievement)) { TC_LOG_ERROR("sql.sql", "Required Achievement %u not exist for map %u difficulty %u, remove quest done requirement.", ar->achievement, mapid, difficulty); ar->achievement = 0; @@ -8588,12 +8588,12 @@ void ObjectMgr::LoadScriptNames() _scriptNamesStore.emplace_back(""); QueryResult result = WorldDatabase.Query( - "SELECT DISTINCT(ScriptName) FROM achievement_criteria_data WHERE ScriptName <> '' AND type = 11 " - "UNION " "SELECT DISTINCT(ScriptName) FROM battleground_template WHERE ScriptName <> '' " "UNION " "SELECT DISTINCT(ScriptName) FROM creature_template WHERE ScriptName <> '' " "UNION " + "SELECT DISTINCT(ScriptName) FROM criteria_data WHERE ScriptName <> '' AND type = 11 " + "UNION " "SELECT DISTINCT(ScriptName) FROM gameobject_template WHERE ScriptName <> '' " "UNION " "SELECT DISTINCT(ScriptName) FROM item_script_names WHERE ScriptName <> '' " @@ -8775,9 +8775,9 @@ void ObjectMgr::LoadFactionChangeAchievements() uint32 alliance = fields[0].GetUInt32(); uint32 horde = fields[1].GetUInt32(); - if (!sAchievementMgr->GetAchievement(alliance)) + if (!sAchievementStore.LookupEntry(alliance)) TC_LOG_ERROR("sql.sql", "Achievement %u (alliance_id) referenced in `player_factionchange_achievement` does not exist, pair skipped!", alliance); - else if (!sAchievementMgr->GetAchievement(horde)) + else if (!sAchievementStore.LookupEntry(horde)) TC_LOG_ERROR("sql.sql", "Achievement %u (horde_id) referenced in `player_factionchange_achievement` does not exist, pair skipped!", horde); else FactionChangeAchievements[alliance] = horde; diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index b95a235bcb6..43763631b0b 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -1417,7 +1417,7 @@ void Group::CountTheRoll(Rolls::iterator rollI) if (player && player->GetSession()) { - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT, roll->itemid, maxresul); + player->UpdateCriteria(CRITERIA_TYPE_ROLL_NEED_ON_LOOT, roll->itemid, maxresul); ItemPosCountVec dest; LootItem* item = &(roll->itemSlot >= roll->getLoot()->items.size() ? roll->getLoot()->quest_items[roll->itemSlot - roll->getLoot()->items.size()] : roll->getLoot()->items[roll->itemSlot]); @@ -1466,7 +1466,7 @@ void Group::CountTheRoll(Rolls::iterator rollI) if (player && player->GetSession()) { - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT, roll->itemid, maxresul); + player->UpdateCriteria(CRITERIA_TYPE_ROLL_GREED_ON_LOOT, roll->itemid, maxresul); LootItem* item = &(roll->itemSlot >= roll->getLoot()->items.size() ? roll->getLoot()->quest_items[roll->itemSlot - roll->getLoot()->items.size()] : roll->getLoot()->items[roll->itemSlot]); @@ -1493,7 +1493,7 @@ void Group::CountTheRoll(Rolls::iterator rollI) roll->getLoot()->NotifyItemRemoved(roll->itemSlot); roll->getLoot()->unlootedCount--; ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(roll->itemid); - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL, 13262); // Disenchant + player->UpdateCriteria(CRITERIA_TYPE_CAST_SPELL, 13262); // Disenchant ItemPosCountVec dest; InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, roll->itemid, item->count); diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp index 586af65ae5a..86a59f04f23 100644 --- a/src/server/game/Guilds/Guild.cpp +++ b/src/server/game/Guilds/Guild.cpp @@ -1391,11 +1391,11 @@ void Guild::HandleSetAchievementTracking(WorldSession* session, std::set<uint32> for (uint32 achievementId : achievementIds) { - if (AchievementEntry const* achievement = sAchievementMgr->GetAchievement(achievementId)) + if (AchievementEntry const* achievement = sAchievementStore.LookupEntry(achievementId)) { - if (AchievementCriteriaTree const* tree = sAchievementMgr->GetAchievementCriteriaTree(achievement->CriteriaTree)) + if (CriteriaTree const* tree = sCriteriaMgr->GetCriteriaTree(achievement->CriteriaTree)) { - sAchievementMgr->WalkCriteriaTree(tree, [&criteriaIds](AchievementCriteriaTree const* node) + CriteriaMgr::WalkCriteriaTree(tree, [&criteriaIds](CriteriaTree const* node) { if (node->Criteria) criteriaIds.insert(node->Criteria->ID); @@ -2162,7 +2162,7 @@ void Guild::SendLoginInfo(WorldSession* session) if (entry->GuildLevel <= GetLevel()) player->LearnSpell(entry->SpellID, true); - m_achievementMgr.SendAllAchievementData(player); + m_achievementMgr.SendAllData(player); WorldPackets::Guild::GuildMemberDailyReset packet; // tells the client to request bank withdrawal limit player->GetSession()->SendPacket(packet.Write()); @@ -3384,9 +3384,9 @@ bool Guild::HasAchieved(uint32 achievementId) const return m_achievementMgr.HasAchieved(achievementId); } -void Guild::UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit* unit, Player* player) +void Guild::UpdateCriteria(CriteriaTypes type, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit* unit, Player* player) { - m_achievementMgr.UpdateAchievementCriteria(type, miscValue1, miscValue2, miscValue3, unit, player); + m_achievementMgr.UpdateCriteria(type, miscValue1, miscValue2, miscValue3, unit, player); } void Guild::HandleNewsSetSticky(WorldSession* session, uint32 newsId, bool sticky) diff --git a/src/server/game/Guilds/Guild.h b/src/server/game/Guilds/Guild.h index d41a4f7c726..db20f48c3e7 100644 --- a/src/server/game/Guilds/Guild.h +++ b/src/server/game/Guilds/Guild.h @@ -865,8 +865,8 @@ public: // Bank tabs void SetBankTabText(uint8 tabId, std::string const& text); - AchievementMgr<Guild>& GetAchievementMgr() { return m_achievementMgr; } - AchievementMgr<Guild> const& GetAchievementMgr() const { return m_achievementMgr; } + GuildAchievementMgr& GetAchievementMgr() { return m_achievementMgr; } + GuildAchievementMgr const& GetAchievementMgr() const { return m_achievementMgr; } // Guild leveling uint8 GetLevel() const { return _level; } @@ -877,7 +877,7 @@ public: void ResetTimes(bool weekly); bool HasAchieved(uint32 achievementId) const; - void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit* unit, Player* player); + void UpdateCriteria(CriteriaTypes type, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit* unit, Player* player); protected: ObjectGuid::LowType m_id; @@ -899,7 +899,7 @@ protected: LogHolder* m_eventLog; LogHolder* m_bankEventLog[GUILD_BANK_MAX_TABS + 1]; LogHolder* m_newsLog; - AchievementMgr<Guild> m_achievementMgr; + GuildAchievementMgr m_achievementMgr; uint8 _level; diff --git a/src/server/game/Guilds/GuildMgr.cpp b/src/server/game/Guilds/GuildMgr.cpp index 8cafc8cdd2f..6af809dcedb 100644 --- a/src/server/game/Guilds/GuildMgr.cpp +++ b/src/server/game/Guilds/GuildMgr.cpp @@ -511,7 +511,7 @@ void GuildMgr::LoadGuildRewards() uint32 requiredAchievementId = fields[0].GetUInt32(); - if (!sAchievementMgr->GetAchievement(requiredAchievementId)) + if (!sAchievementStore.LookupEntry(requiredAchievementId)) { TC_LOG_ERROR("server.loading", "Guild rewards constains not existing achievement entry %u", requiredAchievementId); continue; diff --git a/src/server/game/Handlers/AuctionHouseHandler.cpp b/src/server/game/Handlers/AuctionHouseHandler.cpp index f0e2d8693b0..43a0baa75a7 100644 --- a/src/server/game/Handlers/AuctionHouseHandler.cpp +++ b/src/server/game/Handlers/AuctionHouseHandler.cpp @@ -279,7 +279,7 @@ void WorldSession::HandleAuctionSellItem(WorldPackets::AuctionHouse::AuctionSell SendAuctionCommandResult(AH, AUCTION_SELL_ITEM, ERR_AUCTION_OK); - GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); + GetPlayer()->UpdateCriteria(CRITERIA_TYPE_CREATE_AUCTION, 1); } else // Required stack size of auction does not match to current item stack size, clone item and set correct stack size { @@ -354,7 +354,7 @@ void WorldSession::HandleAuctionSellItem(WorldPackets::AuctionHouse::AuctionSell SendAuctionCommandResult(AH, AUCTION_SELL_ITEM, ERR_AUCTION_OK); - GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); + GetPlayer()->UpdateCriteria(CRITERIA_TYPE_CREATE_AUCTION, 1); } } @@ -437,7 +437,7 @@ void WorldSession::HandleAuctionPlaceBid(WorldPackets::AuctionHouse::AuctionPlac auction->bidder = player->GetGUID().GetCounter(); auction->bid = packet.BidAmount; - GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID, packet.BidAmount); + GetPlayer()->UpdateCriteria(CRITERIA_TYPE_HIGHEST_AUCTION_BID, packet.BidAmount); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_AUCTION_BID); stmt->setUInt64(0, auction->bidder); @@ -466,7 +466,7 @@ void WorldSession::HandleAuctionPlaceBid(WorldPackets::AuctionHouse::AuctionPlac } auction->bidder = player->GetGUID().GetCounter(); auction->bid = auction->buyout; - GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID, auction->buyout); + GetPlayer()->UpdateCriteria(CRITERIA_TYPE_HIGHEST_AUCTION_BID, auction->buyout); SendAuctionCommandResult(auction, AUCTION_PLACE_BID, ERR_AUCTION_OK); diff --git a/src/server/game/Handlers/BankHandler.cpp b/src/server/game/Handlers/BankHandler.cpp index 38f5862b3b6..65321cd6fa8 100644 --- a/src/server/game/Handlers/BankHandler.cpp +++ b/src/server/game/Handlers/BankHandler.cpp @@ -159,7 +159,7 @@ void WorldSession::HandleBuyBankSlotOpcode(WorldPackets::Bank::BuyBankSlot& pack data << uint32(ERR_BANKSLOT_OK); SendPacket(&data); - _player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT); + _player->UpdateCriteria(CRITERIA_TYPE_BUY_BANK_SLOT); } void WorldSession::SendShowBank(ObjectGuid guid) diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index dff529891b6..ee75a4ed58c 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -1133,7 +1133,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) m_playerLoading.Clear(); // Handle Login-Achievements (should be handled after loading) - _player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN, 1); + _player->UpdateCriteria(CRITERIA_TYPE_ON_LOGIN, 1); sScriptMgr->OnPlayerLogin(pCurrChar, firstLogin); @@ -1460,7 +1460,7 @@ void WorldSession::HandleAlterAppearance(WorldPackets::Character::AlterApperance SendBarberShopResult(BARBER_SHOP_RESULT_SUCCESS); _player->ModifyMoney(-int64(cost)); // it isn't free - _player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER, cost); + _player->UpdateCriteria(CRITERIA_TYPE_GOLD_SPENT_AT_BARBER, cost); _player->SetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_HAIR_STYLE_ID, uint8(bs_hair->Data)); _player->SetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_HAIR_COLOR_ID, uint8(packet.NewHairColor)); @@ -1470,7 +1470,7 @@ void WorldSession::HandleAlterAppearance(WorldPackets::Character::AlterApperance if (bs_face) _player->SetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_FACE_ID, uint8(bs_face->Data)); - _player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP, 1); + _player->UpdateCriteria(CRITERIA_TYPE_VISIT_BARBER_SHOP, 1); _player->SetStandState(UNIT_STAND_STATE_STAND); } @@ -2051,8 +2051,8 @@ void WorldSession::HandleCharRaceOrFactionChangeCallback(PreparedQueryResult res trans->Append(stmt); stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_ACHIEVEMENT); - stmt->setUInt16(0, uint16(newTeamId == TEAM_ALLIANCE ? achiev_alliance : achiev_horde)); - stmt->setUInt16(1, uint16(newTeamId == TEAM_ALLIANCE ? achiev_horde : achiev_alliance)); + stmt->setUInt32(0, uint16(newTeamId == TEAM_ALLIANCE ? achiev_alliance : achiev_horde)); + stmt->setUInt32(1, uint16(newTeamId == TEAM_ALLIANCE ? achiev_horde : achiev_alliance)); stmt->setUInt64(2, lowGuid); trans->Append(stmt); } diff --git a/src/server/game/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp index 2c77d8df04d..2d5099fa341 100644 --- a/src/server/game/Handlers/ChatHandler.cpp +++ b/src/server/game/Handlers/ChatHandler.cpp @@ -627,7 +627,7 @@ void WorldSession::HandleTextEmoteOpcode(WorldPackets::Chat::CTextEmote& packet) Unit* unit = ObjectAccessor::GetUnit(*_player, packet.Target); - _player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE, packet.SoundIndex, 0, 0, unit); + _player->UpdateCriteria(CRITERIA_TYPE_DO_EMOTE, packet.SoundIndex, 0, 0, unit); // Send scripted event call if (unit) diff --git a/src/server/game/Handlers/GroupHandler.cpp b/src/server/game/Handlers/GroupHandler.cpp index ec29083d2f8..097a1979400 100644 --- a/src/server/game/Handlers/GroupHandler.cpp +++ b/src/server/game/Handlers/GroupHandler.cpp @@ -376,10 +376,10 @@ void WorldSession::HandleLootRoll(WorldPackets::Loot::LootRoll& packet) switch (packet.RollType) { case ROLL_NEED: - GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED, 1); + GetPlayer()->UpdateCriteria(CRITERIA_TYPE_ROLL_NEED, 1); break; case ROLL_GREED: - GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED, 1); + GetPlayer()->UpdateCriteria(CRITERIA_TYPE_ROLL_GREED, 1); break; } } diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp index f253b4733e7..8c7f8190e09 100644 --- a/src/server/game/Handlers/ItemHandler.cpp +++ b/src/server/game/Handlers/ItemHandler.cpp @@ -437,7 +437,7 @@ void WorldSession::HandleSellItemOpcode(WorldPackets::Item::SellItem& packet) uint32 money = pProto->GetSellPrice() * packet.Amount; _player->ModifyMoney(money); - _player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS, money); + _player->UpdateCriteria(CRITERIA_TYPE_MONEY_FROM_VENDORS, money); } else _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, packet.ItemGUID); @@ -481,7 +481,7 @@ void WorldSession::HandleBuybackItem(WorldPackets::Item::BuyBackItem& packet) _player->ModifyMoney(-(int32)price); _player->RemoveItemFromBuyBackSlot(packet.Slot, false); _player->ItemAddedQuestCheck(pItem->GetEntry(), pItem->GetCount()); - _player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM, pItem->GetEntry(), pItem->GetCount()); + _player->UpdateCriteria(CRITERIA_TYPE_RECEIVE_EPIC_ITEM, pItem->GetEntry(), pItem->GetCount()); _player->StoreItem(dest, pItem, true); } else diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp index 0d497089f75..f4772b1b347 100644 --- a/src/server/game/Handlers/LootHandler.cpp +++ b/src/server/game/Handlers/LootHandler.cpp @@ -185,7 +185,7 @@ void WorldSession::HandleLootMoneyOpcode(WorldPackets::Loot::LootMoney& /*packet for (std::vector<Player*>::const_iterator i = playersNear.begin(); i != playersNear.end(); ++i) { (*i)->ModifyMoney(goldPerPlayer); - (*i)->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY, goldPerPlayer); + (*i)->UpdateCriteria(CRITERIA_TYPE_LOOT_MONEY, goldPerPlayer); if (Guild* guild = sGuildMgr->GetGuildById((*i)->GetGuildId())) if (uint32 guildGold = CalculatePct(goldPerPlayer, (*i)->GetTotalAuraModifier(SPELL_AURA_DEPOSIT_BONUS_MONEY_IN_GUILD_BANK_ON_LOOT))) @@ -200,7 +200,7 @@ void WorldSession::HandleLootMoneyOpcode(WorldPackets::Loot::LootMoney& /*packet else { player->ModifyMoney(loot->gold); - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY, loot->gold); + player->UpdateCriteria(CRITERIA_TYPE_LOOT_MONEY, loot->gold); if (Guild* guild = sGuildMgr->GetGuildById(player->GetGuildId())) if (uint32 guildGold = CalculatePct(loot->gold, player->GetTotalAuraModifier(SPELL_AURA_DEPOSIT_BONUS_MONEY_IN_GUILD_BANK_ON_LOOT))) @@ -471,9 +471,9 @@ void WorldSession::HandleLootMasterGiveOpcode(WorldPacket& recvData) // now move item from loot to target inventory Item* newitem = target->StoreNewItem(dest, item.itemid, true, item.randomPropertyId, item.GetAllowedLooters(), item.BonusListIDs); target->SendNewItem(newitem, uint32(item.count), false, false, true); - target->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, item.itemid, item.count); - target->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE, item.itemid, item.count, loot->loot_type); - target->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM, item.itemid, item.count); + target->UpdateCriteria(CRITERIA_TYPE_LOOT_ITEM, item.itemid, item.count); + target->UpdateCriteria(CRITERIA_TYPE_LOOT_TYPE, item.itemid, item.count, loot->loot_type); + target->UpdateCriteria(CRITERIA_TYPE_LOOT_EPIC_ITEM, item.itemid, item.count); // mark as looted item.count = 0; diff --git a/src/server/game/Handlers/MailHandler.cpp b/src/server/game/Handlers/MailHandler.cpp index 40cc854d740..81221599b2c 100644 --- a/src/server/game/Handlers/MailHandler.cpp +++ b/src/server/game/Handlers/MailHandler.cpp @@ -274,7 +274,7 @@ void WorldSession::HandleSendMail(WorldPackets::Mail::SendMail& packet) player->SendMailResult(0, MAIL_SEND, MAIL_OK); player->ModifyMoney(-reqmoney); - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL, cost); + player->UpdateCriteria(CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL, cost); bool needItemDelay = false; diff --git a/src/server/game/Handlers/QuestHandler.cpp b/src/server/game/Handlers/QuestHandler.cpp index cb56a81e5d9..bfa0bc3db16 100644 --- a/src/server/game/Handlers/QuestHandler.cpp +++ b/src/server/game/Handlers/QuestHandler.cpp @@ -436,7 +436,7 @@ void WorldSession::HandleQuestLogRemoveQuest(WorldPackets::Quest::QuestLogRemove _player->TakeQuestSourceItem(questId, true); // remove quest src item from player _player->RemoveActiveQuest(questId); - _player->RemoveTimedAchievement(ACHIEVEMENT_TIMED_TYPE_QUEST, questId); + _player->RemoveCriteriaTimer(CRITERIA_TIMED_TYPE_QUEST, questId); TC_LOG_INFO("network", "%s abandoned quest %u", _player->GetGUID().ToString().c_str(), questId); @@ -454,7 +454,7 @@ void WorldSession::HandleQuestLogRemoveQuest(WorldPackets::Quest::QuestLogRemove _player->SetQuestSlot(packet.Entry, 0); - _player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED, 1); + _player->UpdateCriteria(CRITERIA_TYPE_QUEST_ABANDONED, 1); } } diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp index 4a28c076ce6..7d639d57f80 100644 --- a/src/server/game/Handlers/SpellHandler.cpp +++ b/src/server/game/Handlers/SpellHandler.cpp @@ -238,7 +238,7 @@ void WorldSession::HandleGameobjectReportUse(WorldPackets::GameObject::GameObjRe if (go->AI()->GossipHello(_player)) return; - _player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT, go->GetEntry()); + _player->UpdateCriteria(CRITERIA_TYPE_USE_GAMEOBJECT, go->GetEntry()); } } diff --git a/src/server/game/Instances/InstanceScript.cpp b/src/server/game/Instances/InstanceScript.cpp index 2969d5666ac..dc008aa881e 100644 --- a/src/server/game/Instances/InstanceScript.cpp +++ b/src/server/game/Instances/InstanceScript.cpp @@ -538,36 +538,36 @@ void InstanceScript::DoSendNotifyToInstance(char const* format, ...) } // Update Achievement Criteria for all players in instance -void InstanceScript::DoUpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscValue1 /*= 0*/, uint32 miscValue2 /*= 0*/, Unit* unit /*= NULL*/) +void InstanceScript::DoUpdateCriteria(CriteriaTypes type, uint32 miscValue1 /*= 0*/, uint32 miscValue2 /*= 0*/, Unit* unit /*= NULL*/) { Map::PlayerList const &PlayerList = instance->GetPlayers(); if (!PlayerList.isEmpty()) for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) if (Player* player = i->GetSource()) - player->UpdateAchievementCriteria(type, miscValue1, miscValue2, 0, unit); + player->UpdateCriteria(type, miscValue1, miscValue2, 0, unit); } // Start timed achievement for all players in instance -void InstanceScript::DoStartTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry) +void InstanceScript::DoStartCriteriaTimer(CriteriaTimedTypes type, uint32 entry) { Map::PlayerList const &PlayerList = instance->GetPlayers(); if (!PlayerList.isEmpty()) for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) if (Player* player = i->GetSource()) - player->StartTimedAchievement(type, entry); + player->StartCriteriaTimer(type, entry); } // Stop timed achievement for all players in instance -void InstanceScript::DoStopTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry) +void InstanceScript::DoStopCriteriaTimer(CriteriaTimedTypes type, uint32 entry) { Map::PlayerList const &PlayerList = instance->GetPlayers(); if (!PlayerList.isEmpty()) for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) if (Player* player = i->GetSource()) - player->RemoveTimedAchievement(type, entry); + player->RemoveCriteriaTimer(type, entry); } // Remove Auras due to Spell on all players in instance diff --git a/src/server/game/Instances/InstanceScript.h b/src/server/game/Instances/InstanceScript.h index 7a2daaaecf8..92c7be92752 100644 --- a/src/server/game/Instances/InstanceScript.h +++ b/src/server/game/Instances/InstanceScript.h @@ -210,11 +210,11 @@ class TC_GAME_API InstanceScript : public ZoneScript void DoSendNotifyToInstance(char const* format, ...); // Update Achievement Criteria for all players in instance - void DoUpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscValue1 = 0, uint32 miscValue2 = 0, Unit* unit = NULL); + void DoUpdateCriteria(CriteriaTypes type, uint32 miscValue1 = 0, uint32 miscValue2 = 0, Unit* unit = NULL); // Start/Stop Timed Achievement Criteria for all players in instance - void DoStartTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry); - void DoStopTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry); + void DoStartCriteriaTimer(CriteriaTimedTypes type, uint32 entry); + void DoStopCriteriaTimer(CriteriaTimedTypes type, uint32 entry); // Remove Auras due to Spell on all players in instance void DoRemoveAurasDueToSpellOnPlayers(uint32 spell); diff --git a/src/server/game/Maps/MapManager.cpp b/src/server/game/Maps/MapManager.cpp index 985ce1af681..3acd04543ad 100644 --- a/src/server/game/Maps/MapManager.cpp +++ b/src/server/game/Maps/MapManager.cpp @@ -34,7 +34,6 @@ #include "Player.h" #include "WorldSession.h" #include "Opcodes.h" -#include "AchievementMgr.h" #include "MiscPackets.h" MapManager::MapManager() @@ -370,5 +369,4 @@ void MapManager::FreeInstanceId(uint32 instanceId) SetNextInstanceId(instanceId); _instanceIds[instanceId] = false; - sAchievementMgr->OnInstanceDestroyed(instanceId); } diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp index d6d54f052e9..4d6383e5931 100755 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp @@ -370,7 +370,7 @@ bool FlightPathMovementGenerator::DoUpdate(Player* player, uint32 /*diff*/) player->m_taxi.NextTaxiDestination(); if (!_pointsForPathSwitch.empty()) { - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING, _pointsForPathSwitch.front().Cost); + player->UpdateCriteria(CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING, _pointsForPathSwitch.front().Cost); player->ModifyMoney(-_pointsForPathSwitch.front().Cost); } } diff --git a/src/server/game/Reputation/ReputationMgr.cpp b/src/server/game/Reputation/ReputationMgr.cpp index be0714b2747..ceecf1a9b85 100644 --- a/src/server/game/Reputation/ReputationMgr.cpp +++ b/src/server/game/Reputation/ReputationMgr.cpp @@ -367,11 +367,11 @@ bool ReputationMgr::SetOneFactionReputation(FactionEntry const* factionEntry, in UpdateRankCounters(old_rank, new_rank); _player->ReputationChanged(factionEntry); - _player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KNOWN_FACTIONS, factionEntry->ID); - _player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION, factionEntry->ID); - _player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION, factionEntry->ID); - _player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_REVERED_REPUTATION, factionEntry->ID); - _player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_HONORED_REPUTATION, factionEntry->ID); + _player->UpdateCriteria(CRITERIA_TYPE_KNOWN_FACTIONS, factionEntry->ID); + _player->UpdateCriteria(CRITERIA_TYPE_GAIN_REPUTATION, factionEntry->ID); + _player->UpdateCriteria(CRITERIA_TYPE_GAIN_EXALTED_REPUTATION, factionEntry->ID); + _player->UpdateCriteria(CRITERIA_TYPE_GAIN_REVERED_REPUTATION, factionEntry->ID); + _player->UpdateCriteria(CRITERIA_TYPE_GAIN_HONORED_REPUTATION, factionEntry->ID); return true; } diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index c89ff4b2c7a..594221099d6 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -2527,15 +2527,15 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA if (Player* player = unit->ToPlayer()) { - player->StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_SPELL_TARGET, m_spellInfo->Id); - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, m_spellInfo->Id, 0, 0, m_caster); - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2, m_spellInfo->Id); + player->StartCriteriaTimer(CRITERIA_TIMED_TYPE_SPELL_TARGET, m_spellInfo->Id); + player->UpdateCriteria(CRITERIA_TYPE_BE_SPELL_TARGET, m_spellInfo->Id, 0, 0, m_caster); + player->UpdateCriteria(CRITERIA_TYPE_BE_SPELL_TARGET2, m_spellInfo->Id); } if (Player* player = m_caster->ToPlayer()) { - player->StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_SPELL_CASTER, m_spellInfo->Id); - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2, m_spellInfo->Id, 0, 0, unit); + player->StartCriteriaTimer(CRITERIA_TIMED_TYPE_SPELL_CASTER, m_spellInfo->Id); + player->UpdateCriteria(CRITERIA_TYPE_CAST_SPELL2, m_spellInfo->Id, 0, 0, unit); } if (m_caster != unit) @@ -3270,11 +3270,11 @@ void Spell::cast(bool skipCheck) { if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CAST_ITEM) && m_CastItem) { - player->StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_ITEM, m_CastItem->GetEntry()); - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM, m_CastItem->GetEntry()); + player->StartCriteriaTimer(CRITERIA_TIMED_TYPE_ITEM, m_CastItem->GetEntry()); + player->UpdateCriteria(CRITERIA_TYPE_USE_ITEM, m_CastItem->GetEntry()); } - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL, m_spellInfo->Id); + player->UpdateCriteria(CRITERIA_TYPE_CAST_SPELL, m_spellInfo->Id); } if (!(_triggeredCastFlags & TRIGGERED_IGNORE_POWER_AND_REAGENT_COST)) diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 2b316f15572..b274750c5ab 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -2211,7 +2211,7 @@ void Spell::EffectLearnSpell(SpellEffIndex effIndex) if (entry->SummonSpellID == spellToLearn) { battlePetMgr->AddPet(entry->ID, entry->CreatureID, BattlePetMgr::RollPetBreed(entry->ID), BattlePetMgr::GetDefaultPetQuality(entry->ID)); - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_OWN_BATTLE_PET_COUNT); + player->UpdateCriteria(CRITERIA_TYPE_OWN_BATTLE_PET_COUNT); break; } } diff --git a/src/server/game/Tools/CharacterDatabaseCleaner.cpp b/src/server/game/Tools/CharacterDatabaseCleaner.cpp index 7fa56b77900..255900b5414 100644 --- a/src/server/game/Tools/CharacterDatabaseCleaner.cpp +++ b/src/server/game/Tools/CharacterDatabaseCleaner.cpp @@ -17,7 +17,7 @@ */ #include "Common.h" -#include "AchievementMgr.h" +#include "CriteriaHandler.h" #include "CharacterDatabaseCleaner.h" #include "World.h" #include "Database/DatabaseEnv.h" @@ -109,7 +109,7 @@ void CharacterDatabaseCleaner::CheckUnique(const char* column, const char* table bool CharacterDatabaseCleaner::AchievementProgressCheck(uint32 criteria) { - return sAchievementMgr->GetAchievementCriteria(criteria) != nullptr; + return sCriteriaMgr->GetCriteria(criteria) != nullptr; } void CharacterDatabaseCleaner::CleanCharacterAchievementProgress() diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 3fc233b5c3c..61e1755b4e4 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1816,14 +1816,14 @@ void World::SetInitialWorldSettings() TC_LOG_INFO("server.loading", "Loading skill tier info..."); sObjectMgr->LoadSkillTiers(); + TC_LOG_INFO("server.loading", "Loading Criteria Modifier trees..."); + sCriteriaMgr->LoadCriteriaModifiersTree(); + TC_LOG_INFO("server.loading", "Loading Criteria Lists..."); + sCriteriaMgr->LoadCriteriaList(); + TC_LOG_INFO("server.loading", "Loading Criteria Data..."); + sCriteriaMgr->LoadCriteriaData(); 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..."); - sAchievementMgr->LoadAchievementCriteriaData(); TC_LOG_INFO("server.loading", "Loading Achievement Rewards..."); sAchievementMgr->LoadRewards(); TC_LOG_INFO("server.loading", "Loading Achievement Reward Locales..."); diff --git a/src/server/scripts/Commands/cs_achievement.cpp b/src/server/scripts/Commands/cs_achievement.cpp index ef14ca66519..2238c76b5f5 100644 --- a/src/server/scripts/Commands/cs_achievement.cpp +++ b/src/server/scripts/Commands/cs_achievement.cpp @@ -68,7 +68,7 @@ public: return false; } - if (AchievementEntry const* achievementEntry = sAchievementMgr->GetAchievement(achievementId)) + if (AchievementEntry const* achievementEntry = sAchievementStore.LookupEntry(achievementId)) target->CompletedAchievement(achievementEntry); return true; diff --git a/src/server/scripts/Commands/cs_disable.cpp b/src/server/scripts/Commands/cs_disable.cpp index 54932228372..75b35324c91 100644 --- a/src/server/scripts/Commands/cs_disable.cpp +++ b/src/server/scripts/Commands/cs_disable.cpp @@ -23,7 +23,7 @@ Category: commandscripts EndScriptData */ #include "DisableMgr.h" -#include "AchievementMgr.h" +#include "CriteriaHandler.h" #include "Chat.h" #include "Language.h" #include "ObjectMgr.h" @@ -41,25 +41,25 @@ public: { static std::vector<ChatCommand> removeDisableCommandTable = { - { "spell", rbac::RBAC_PERM_COMMAND_DISABLE_REMOVE_SPELL, true, &HandleRemoveDisableSpellCommand, "" }, - { "quest", rbac::RBAC_PERM_COMMAND_DISABLE_REMOVE_QUEST, true, &HandleRemoveDisableQuestCommand, "" }, - { "map", rbac::RBAC_PERM_COMMAND_DISABLE_REMOVE_MAP, true, &HandleRemoveDisableMapCommand, "" }, - { "battleground", rbac::RBAC_PERM_COMMAND_DISABLE_REMOVE_BATTLEGROUND, true, &HandleRemoveDisableBattlegroundCommand, "" }, - { "achievement_criteria", rbac::RBAC_PERM_COMMAND_DISABLE_REMOVE_ACHIEVEMENT_CRITERIA, true, &HandleRemoveDisableAchievementCriteriaCommand, "" }, - { "outdoorpvp", rbac::RBAC_PERM_COMMAND_DISABLE_REMOVE_OUTDOORPVP, true, &HandleRemoveDisableOutdoorPvPCommand, "" }, - { "vmap", rbac::RBAC_PERM_COMMAND_DISABLE_REMOVE_VMAP, true, &HandleRemoveDisableVmapCommand, "" }, - { "mmap", rbac::RBAC_PERM_COMMAND_DISABLE_REMOVE_MMAP, true, &HandleRemoveDisableMMapCommand, "" }, + { "spell", rbac::RBAC_PERM_COMMAND_DISABLE_REMOVE_SPELL, true, &HandleRemoveDisableSpellCommand, "" }, + { "quest", rbac::RBAC_PERM_COMMAND_DISABLE_REMOVE_QUEST, true, &HandleRemoveDisableQuestCommand, "" }, + { "map", rbac::RBAC_PERM_COMMAND_DISABLE_REMOVE_MAP, true, &HandleRemoveDisableMapCommand, "" }, + { "battleground", rbac::RBAC_PERM_COMMAND_DISABLE_REMOVE_BATTLEGROUND, true, &HandleRemoveDisableBattlegroundCommand, "" }, + { "criteria", rbac::RBAC_PERM_COMMAND_DISABLE_REMOVE_CRITERIA, true, &HandleRemoveDisableCriteriaCommand, "" }, + { "outdoorpvp", rbac::RBAC_PERM_COMMAND_DISABLE_REMOVE_OUTDOORPVP, true, &HandleRemoveDisableOutdoorPvPCommand, "" }, + { "vmap", rbac::RBAC_PERM_COMMAND_DISABLE_REMOVE_VMAP, true, &HandleRemoveDisableVmapCommand, "" }, + { "mmap", rbac::RBAC_PERM_COMMAND_DISABLE_REMOVE_MMAP, true, &HandleRemoveDisableMMapCommand, "" }, }; static std::vector<ChatCommand> addDisableCommandTable = { - { "spell", rbac::RBAC_PERM_COMMAND_DISABLE_ADD_SPELL, true, &HandleAddDisableSpellCommand, "" }, - { "quest", rbac::RBAC_PERM_COMMAND_DISABLE_ADD_QUEST, true, &HandleAddDisableQuestCommand, "" }, - { "map", rbac::RBAC_PERM_COMMAND_DISABLE_ADD_MAP, true, &HandleAddDisableMapCommand, "" }, - { "battleground", rbac::RBAC_PERM_COMMAND_DISABLE_ADD_BATTLEGROUND, true, &HandleAddDisableBattlegroundCommand, "" }, - { "achievement_criteria", rbac::RBAC_PERM_COMMAND_DISABLE_ADD_ACHIEVEMENT_CRITERIA, true, &HandleAddDisableAchievementCriteriaCommand, "" }, - { "outdoorpvp", rbac::RBAC_PERM_COMMAND_DISABLE_ADD_OUTDOORPVP, true, &HandleAddDisableOutdoorPvPCommand, "" }, - { "vmap", rbac::RBAC_PERM_COMMAND_DISABLE_ADD_VMAP, true, &HandleAddDisableVmapCommand, "" }, - { "mmap", rbac::RBAC_PERM_COMMAND_DISABLE_ADD_MMAP, true, &HandleAddDisableMMapCommand, "" }, + { "spell", rbac::RBAC_PERM_COMMAND_DISABLE_ADD_SPELL, true, &HandleAddDisableSpellCommand, "" }, + { "quest", rbac::RBAC_PERM_COMMAND_DISABLE_ADD_QUEST, true, &HandleAddDisableQuestCommand, "" }, + { "map", rbac::RBAC_PERM_COMMAND_DISABLE_ADD_MAP, true, &HandleAddDisableMapCommand, "" }, + { "battleground", rbac::RBAC_PERM_COMMAND_DISABLE_ADD_BATTLEGROUND, true, &HandleAddDisableBattlegroundCommand, "" }, + { "criteria", rbac::RBAC_PERM_COMMAND_DISABLE_ADD_CRITERIA, true, &HandleAddDisableCriteriaCommand, "" }, + { "outdoorpvp", rbac::RBAC_PERM_COMMAND_DISABLE_ADD_OUTDOORPVP, true, &HandleAddDisableOutdoorPvPCommand, "" }, + { "vmap", rbac::RBAC_PERM_COMMAND_DISABLE_ADD_VMAP, true, &HandleAddDisableVmapCommand, "" }, + { "mmap", rbac::RBAC_PERM_COMMAND_DISABLE_ADD_MMAP, true, &HandleAddDisableMMapCommand, "" }, }; static std::vector<ChatCommand> disableCommandTable = { @@ -89,7 +89,7 @@ public: std::string disableComment = commentStr; uint32 entry = uint32(atoi(entryStr)); - std::string disableTypeStr = ""; + char const* disableTypeStr = ""; switch (disableType) { @@ -137,15 +137,15 @@ public: disableTypeStr = "battleground"; break; } - case DISABLE_TYPE_ACHIEVEMENT_CRITERIA: + case DISABLE_TYPE_CRITERIA: { - if (!sAchievementMgr->GetAchievementCriteria(entry)) + if (!sCriteriaMgr->GetCriteria(entry)) { handler->PSendSysMessage(LANG_COMMAND_NO_ACHIEVEMENT_CRITERIA_FOUND); handler->SetSentErrorMessage(true); return false; } - disableTypeStr = "achievement criteria"; + disableTypeStr = "criteria"; break; } case DISABLE_TYPE_OUTDOORPVP: @@ -192,7 +192,7 @@ public: PreparedQueryResult result = WorldDatabase.Query(stmt); if (result) { - handler->PSendSysMessage("This %s (Id: %u) is already disabled.", disableTypeStr.c_str(), entry); + handler->PSendSysMessage("This %s (Id: %u) is already disabled.", disableTypeStr, entry); handler->SetSentErrorMessage(true); return false; } @@ -204,7 +204,7 @@ public: stmt->setString(3, disableComment); WorldDatabase.Execute(stmt); - handler->PSendSysMessage("Add Disabled %s (Id: %u) for reason %s", disableTypeStr.c_str(), entry, disableComment.c_str()); + handler->PSendSysMessage("Add Disabled %s (Id: %u) for reason %s", disableTypeStr, entry, disableComment.c_str()); return true; } @@ -240,12 +240,12 @@ public: return HandleAddDisables(handler, args, DISABLE_TYPE_BATTLEGROUND); } - static bool HandleAddDisableAchievementCriteriaCommand(ChatHandler* handler, char const* args) + static bool HandleAddDisableCriteriaCommand(ChatHandler* handler, char const* args) { if (!*args) return false; - return HandleAddDisables(handler, args, DISABLE_TYPE_ACHIEVEMENT_CRITERIA); + return HandleAddDisables(handler, args, DISABLE_TYPE_CRITERIA); } static bool HandleAddDisableOutdoorPvPCommand(ChatHandler* handler, char const* args) @@ -281,7 +281,7 @@ public: uint32 entry = uint32(atoi(entryStr)); - std::string disableTypeStr = ""; + char const* disableTypeStr = ""; switch (disableType) { @@ -297,8 +297,8 @@ public: case DISABLE_TYPE_BATTLEGROUND: disableTypeStr = "battleground"; break; - case DISABLE_TYPE_ACHIEVEMENT_CRITERIA: - disableTypeStr = "achievement criteria"; + case DISABLE_TYPE_CRITERIA: + disableTypeStr = "criteria"; break; case DISABLE_TYPE_OUTDOORPVP: disableTypeStr = "outdoorpvp"; @@ -318,7 +318,7 @@ public: PreparedQueryResult result = WorldDatabase.Query(stmt); if (!result) { - handler->PSendSysMessage("This %s (Id: %u) is not disabled.", disableTypeStr.c_str(), entry); + handler->PSendSysMessage("This %s (Id: %u) is not disabled.", disableTypeStr, entry); handler->SetSentErrorMessage(true); return false; } @@ -328,7 +328,7 @@ public: stmt->setUInt8(1, disableType); WorldDatabase.Execute(stmt); - handler->PSendSysMessage("Remove Disabled %s (Id: %u)", disableTypeStr.c_str(), entry); + handler->PSendSysMessage("Remove Disabled %s (Id: %u)", disableTypeStr, entry); return true; } @@ -364,12 +364,12 @@ public: return HandleRemoveDisables(handler, args, DISABLE_TYPE_BATTLEGROUND); } - static bool HandleRemoveDisableAchievementCriteriaCommand(ChatHandler* handler, char const* args) + static bool HandleRemoveDisableCriteriaCommand(ChatHandler* handler, char const* args) { if (!*args) return false; - return HandleRemoveDisables(handler, args, DISABLE_TYPE_ACHIEVEMENT_CRITERIA); + return HandleRemoveDisables(handler, args, DISABLE_TYPE_CRITERIA); } static bool HandleRemoveDisableOutdoorPvPCommand(ChatHandler* handler, char const* args) diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp index 4ef4f5807b2..4b185e7d6c5 100644 --- a/src/server/scripts/Commands/cs_reload.cpp +++ b/src/server/scripts/Commands/cs_reload.cpp @@ -67,7 +67,6 @@ public: { { "auctions", rbac::RBAC_PERM_COMMAND_RELOAD_AUCTIONS, true, &HandleReloadAuctionsCommand, "" }, { "access_requirement", rbac::RBAC_PERM_COMMAND_RELOAD_ACCESS_REQUIREMENT, true, &HandleReloadAccessRequirementCommand, "" }, - { "achievement_criteria_data", rbac::RBAC_PERM_COMMAND_RELOAD_ACHIEVEMENT_CRITERIA_DATA, true, &HandleReloadAchievementCriteriaDataCommand, "" }, { "achievement_reward", rbac::RBAC_PERM_COMMAND_RELOAD_ACHIEVEMENT_REWARD, true, &HandleReloadAchievementRewardCommand, "" }, { "all", rbac::RBAC_PERM_COMMAND_RELOAD_ALL, true, NULL, "", reloadAllCommandTable }, { "areatrigger_involvedrelation", rbac::RBAC_PERM_COMMAND_RELOAD_AREATRIGGER_INVOLVEDRELATION, true, &HandleReloadQuestAreaTriggersCommand, "" }, @@ -87,6 +86,7 @@ public: { "creature_queststarter", rbac::RBAC_PERM_COMMAND_RELOAD_CREATURE_QUESTSTARTER, true, &HandleReloadCreatureQuestStarterCommand, "" }, { "creature_summon_groups", rbac::RBAC_PERM_COMMAND_RELOAD_CREATURE_SUMMON_GROUPS, true, &HandleReloadCreatureSummonGroupsCommand, "" }, { "creature_template", rbac::RBAC_PERM_COMMAND_RELOAD_CREATURE_TEMPLATE, true, &HandleReloadCreatureTemplateCommand, "" }, + { "criteria_data", rbac::RBAC_PERM_COMMAND_RELOAD_CRITERIA_DATA, true, &HandleReloadCriteriaDataCommand, "" }, { "disables", rbac::RBAC_PERM_COMMAND_RELOAD_DISABLES, true, &HandleReloadDisablesCommand, "" }, { "disenchant_loot_template", rbac::RBAC_PERM_COMMAND_RELOAD_DISENCHANT_LOOT_TEMPLATE, true, &HandleReloadLootTemplatesDisenchantCommand, "" }, { "event_scripts", rbac::RBAC_PERM_COMMAND_RELOAD_EVENT_SCRIPTS, true, &HandleReloadEventScriptsCommand, "" }, @@ -205,7 +205,7 @@ public: static bool HandleReloadAllAchievementCommand(ChatHandler* handler, const char* /*args*/) { - HandleReloadAchievementCriteriaDataCommand(handler, ""); + HandleReloadCriteriaDataCommand(handler, ""); HandleReloadAchievementRewardCommand(handler, ""); return true; } @@ -333,11 +333,11 @@ public: return true; } - static bool HandleReloadAchievementCriteriaDataCommand(ChatHandler* handler, const char* /*args*/) + static bool HandleReloadCriteriaDataCommand(ChatHandler* handler, const char* /*args*/) { - TC_LOG_INFO("misc", "Re-Loading Additional Achievement Criteria Data..."); - sAchievementMgr->LoadAchievementCriteriaData(); - handler->SendGlobalGMSysMessage("DB table `achievement_criteria_data` reloaded."); + TC_LOG_INFO("misc", "Re-Loading Additional Criteria Data..."); + sCriteriaMgr->LoadCriteriaData(); + handler->SendGlobalGMSysMessage("DB table `criteria_data` reloaded."); return true; } diff --git a/src/server/scripts/Commands/cs_reset.cpp b/src/server/scripts/Commands/cs_reset.cpp index a1699a183da..e77893e9de6 100644 --- a/src/server/scripts/Commands/cs_reset.cpp +++ b/src/server/scripts/Commands/cs_reset.cpp @@ -64,7 +64,7 @@ public: if (target) target->ResetAchievements(); else - AchievementMgr<Player>::DeleteFromDB(targetGuid); + PlayerAchievementMgr::DeleteFromDB(targetGuid); return true; } @@ -77,7 +77,7 @@ public: target->SetUInt32Value(PLAYER_FIELD_KILLS, 0); target->SetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS, 0); - target->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL); + target->UpdateCriteria(CRITERIA_TYPE_EARN_HONORABLE_KILL); return true; } diff --git a/src/server/scripts/Kalimdor/HallsOfOrigination/boss_anraphet.cpp b/src/server/scripts/Kalimdor/HallsOfOrigination/boss_anraphet.cpp index 925eb8308aa..a75e23104d7 100644 --- a/src/server/scripts/Kalimdor/HallsOfOrigination/boss_anraphet.cpp +++ b/src/server/scripts/Kalimdor/HallsOfOrigination/boss_anraphet.cpp @@ -384,7 +384,7 @@ class npc_brann_bronzebeard_anraphet : public CreatureScript case EVENT_BRANN_UNLOCK_DOOR: Talk(BRANN_SAY_UNLOCK_DOOR); _instance->SetBossState(DATA_VAULT_OF_LIGHTS, DONE); - _instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_VAULT_OF_LIGHTS_EVENT); + _instance->DoStartCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, ACHIEV_VAULT_OF_LIGHTS_EVENT); events.ScheduleEvent(EVENT_BRANN_MOVE_INTRO, 3500); break; case EVENT_BRANN_THINK: diff --git a/src/server/scripts/Kalimdor/OnyxiasLair/boss_onyxia.cpp b/src/server/scripts/Kalimdor/OnyxiasLair/boss_onyxia.cpp index 71ebe870e3d..56157afc9bd 100644 --- a/src/server/scripts/Kalimdor/OnyxiasLair/boss_onyxia.cpp +++ b/src/server/scripts/Kalimdor/OnyxiasLair/boss_onyxia.cpp @@ -155,7 +155,7 @@ public: _Reset(); me->SetReactState(REACT_AGGRESSIVE); instance->SetData(DATA_ONYXIA_PHASE, Phase); - instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); + instance->DoStopCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); } void EnterCombat(Unit* /*who*/) override @@ -166,7 +166,7 @@ public: events.ScheduleEvent(EVENT_TAIL_SWEEP, urand(15000, 20000)); events.ScheduleEvent(EVENT_CLEAVE, urand(2000, 5000)); events.ScheduleEvent(EVENT_WING_BUFFET, urand(10000, 20000)); - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); + instance->DoStartCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); } void JustSummoned(Creature* summoned) override diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_herald_volazj.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_herald_volazj.cpp index f077c433a93..53a061f49cf 100644 --- a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_herald_volazj.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_herald_volazj.cpp @@ -165,7 +165,7 @@ public: Initialize(); instance->SetBossState(DATA_HERALD_VOLAZJ, NOT_STARTED); - instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_QUICK_DEMISE_START_EVENT); + instance->DoStopCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, ACHIEV_QUICK_DEMISE_START_EVENT); // Visible for all players in insanity me->SetInPhase(169, true, true); @@ -185,7 +185,7 @@ public: Talk(SAY_AGGRO); instance->SetBossState(DATA_HERALD_VOLAZJ, IN_PROGRESS); - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_QUICK_DEMISE_START_EVENT); + instance->DoStartCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, ACHIEV_QUICK_DEMISE_START_EVENT); } void JustSummoned(Creature* summon) override diff --git a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp index 16cfb30e2dc..3f4c8fc9d3d 100644 --- a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp @@ -144,7 +144,7 @@ public: Summons.DespawnAll(); instance->SetBossState(DATA_ANUBARAK, NOT_STARTED); - instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); + instance->DoStopCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); } Creature* DoSummonImpaleTarget(Unit* target) @@ -167,7 +167,7 @@ public: { Talk(SAY_AGGRO); DelayTimer = 0; - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); + instance->DoStartCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); } void DelayEventStart() diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp index 83bd1c8fbcb..8fbe5e7803d 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp @@ -371,7 +371,7 @@ class boss_fjola : public CreatureScript TouchSpellId = SPELL_LIGHT_TOUCH; SpikeSpellId = SPELL_LIGHT_TWIN_SPIKE; - instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, EVENT_START_TWINS_FIGHT); + instance->DoStopCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, EVENT_START_TWINS_FIGHT); boss_twin_baseAI::Reset(); } @@ -410,7 +410,7 @@ class boss_fjola : public CreatureScript void EnterCombat(Unit* who) override { - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, EVENT_START_TWINS_FIGHT); + instance->DoStartCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, EVENT_START_TWINS_FIGHT); events.ScheduleEvent(EVENT_SPECIAL_ABILITY, 45 * IN_MILLISECONDS); me->SummonCreature(NPC_BULLET_CONTROLLER, ToCCommonLoc[1].GetPositionX(), ToCCommonLoc[1].GetPositionY(), ToCCommonLoc[1].GetPositionZ(), 0.0f, TEMPSUMMON_MANUAL_DESPAWN); boss_twin_baseAI::EnterCombat(who); diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp index b053d95e1bd..904e07cbc33 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp @@ -238,9 +238,9 @@ class instance_trial_of_the_crusader : public InstanceMapScript state = IN_PROGRESS; break; case DONE: - DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, SPELL_DEFEAT_FACTION_CHAMPIONS); + DoUpdateCriteria(CRITERIA_TYPE_BE_SPELL_TARGET, SPELL_DEFEAT_FACTION_CHAMPIONS); if (ResilienceWillFixItTimer > 0) - DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, SPELL_CHAMPIONS_KILLED_IN_MINUTE); + DoUpdateCriteria(CRITERIA_TYPE_BE_SPELL_TARGET, SPELL_CHAMPIONS_KILLED_IN_MINUTE); DoRespawnGameObject(CrusadersCacheGUID, 7*DAY); if (GameObject* cache = instance->GetGameObject(CrusadersCacheGUID)) cache->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); @@ -408,7 +408,7 @@ class instance_trial_of_the_crusader : public InstanceMapScript break; case SNAKES_DONE: if (NotOneButTwoJormungarsTimer > 0) - DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, SPELL_WORMS_KILLED_IN_10_SECONDS); + DoUpdateCriteria(CRITERIA_TYPE_BE_SPELL_TARGET, SPELL_WORMS_KILLED_IN_10_SECONDS); EventStage = 300; SetData(TYPE_NORTHREND_BEASTS, IN_PROGRESS); break; diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp index 41c79f17dbf..106c567b24e 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp @@ -815,7 +815,7 @@ class npc_jaina_or_sylvanas_escape_hor : public CreatureScript _events.Reset(); _icewall = 0; _events.ScheduleEvent(EVENT_ESCAPE, 1000); - _instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_NOT_RETREATING_EVENT); + _instance->DoStopCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, ACHIEV_NOT_RETREATING_EVENT); } void JustDied(Unit* /*killer*/) override @@ -1053,7 +1053,7 @@ class npc_jaina_or_sylvanas_escape_hor : public CreatureScript } } _invincibility = false; - _instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_NOT_RETREATING_EVENT); + _instance->DoStartCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, ACHIEV_NOT_RETREATING_EVENT); _events.ScheduleEvent(EVENT_ESCAPE_7, 1000); break; case EVENT_ESCAPE_7: diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp index c6570da1132..d78a3ac7ffe 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp @@ -349,7 +349,7 @@ class instance_halls_of_reflection : public InstanceMapScript } break; case FAIL: - DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_NOT_RETREATING_EVENT); + DoStopCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, ACHIEV_NOT_RETREATING_EVENT); if (Creature* jainaOrSylvanas = instance->GetCreature(JainaOrSylvanasEscapeGUID)) jainaOrSylvanas->DespawnOrUnsummon(10000); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp index 745a90fef5e..8764f7ed86c 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp @@ -322,7 +322,7 @@ class boss_lady_deathwhisper : public CreatureScript livingAddEntries.insert(unit->GetEntry()); if (livingAddEntries.size() >= 5) - instance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, SPELL_FULL_HOUSE, 0, me); + instance->DoUpdateCriteria(CRITERIA_TYPE_BE_SPELL_TARGET, SPELL_FULL_HOUSE, 0, me); if (Creature* darnavan = ObjectAccessor::GetCreature(*me, _darnavanGUID)) { diff --git a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp index 1b485f588ec..10a1d0b4650 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp @@ -151,7 +151,7 @@ public: _JustDied(); // start achievement timer (kill Maexna within 20 min) - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); + instance->DoStartCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); } void EnterCombat(Unit* /*who*/) override diff --git a/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp b/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp index 5acd958217c..d655ee17316 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp @@ -286,7 +286,7 @@ struct boss_four_horsemen_baseAI : public BossAI if (instance->GetBossState(BOSS_HORSEMEN) == DONE) return; instance->SetBossState(BOSS_HORSEMEN, DONE); - //instance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, SPELL_ENCOUNTER_CREDIT); + //instance->DoUpdateCriteria(CRITERIA_TYPE_BE_SPELL_TARGET, SPELL_ENCOUNTER_CREDIT); DoCastAOE(SPELL_ENCOUNTER_CREDIT, true); } diff --git a/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp b/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp index adbe5fdbcdc..c360947be3a 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp @@ -77,7 +77,7 @@ public: { _Reset(); - instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_MAKE_QUICK_WERK_OF_HIM_STARTING_EVENT); + instance->DoStopCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, ACHIEV_MAKE_QUICK_WERK_OF_HIM_STARTING_EVENT); } void KilledUnit(Unit* /*Victim*/) override @@ -100,7 +100,7 @@ public: events.ScheduleEvent(EVENT_HATEFUL, Seconds(1)); events.ScheduleEvent(EVENT_BERSERK, Minutes(6)); - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_MAKE_QUICK_WERK_OF_HIM_STARTING_EVENT); + instance->DoStartCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, ACHIEV_MAKE_QUICK_WERK_OF_HIM_STARTING_EVENT); } void UpdateAI(uint32 diff) override diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp index 1e17aec42f7..6df0380000a 100644 --- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp +++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp @@ -383,7 +383,7 @@ public: SetPhase(PHASE_NOT_STARTED, true); me->SetReactState(REACT_PASSIVE); - instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); + instance->DoStopCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); } uint32 GetData(uint32 data) const override @@ -582,7 +582,7 @@ public: Talk(SAY_START_P_ONE); DoCast(SPELL_BERSERK); // periodic aura, first tick in 10 minutes - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); + instance->DoStartCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); } void EnterEvadeMode(EvadeReason /*why*/) override diff --git a/src/server/scripts/Northrend/Nexus/Oculus/boss_drakos.cpp b/src/server/scripts/Northrend/Nexus/Oculus/boss_drakos.cpp index adc9ff2fbb0..0ee7b2e7649 100644 --- a/src/server/scripts/Northrend/Nexus/Oculus/boss_drakos.cpp +++ b/src/server/scripts/Northrend/Nexus/Oculus/boss_drakos.cpp @@ -133,7 +133,7 @@ class boss_drakos : public CreatureScript Talk(SAY_DEATH); // start achievement timer (kill Eregos within 20 min) - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); + instance->DoStartCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); } void KilledUnit(Unit* /*victim*/) override diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_loken.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_loken.cpp index d6c87a4edf8..6e525fb4bb3 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_loken.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_loken.cpp @@ -97,7 +97,7 @@ public: { Initialize(); _Reset(); - instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMELY_DEATH_START_EVENT); + instance->DoStopCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, ACHIEV_TIMELY_DEATH_START_EVENT); } void EnterCombat(Unit* /*who*/) override @@ -108,7 +108,7 @@ public: events.ScheduleEvent(EVENT_ARC_LIGHTNING, 15000); events.ScheduleEvent(EVENT_LIGHTNING_NOVA, 20000); events.ScheduleEvent(EVENT_RESUME_PULSING_SHOCKWAVE, 1000); - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMELY_DEATH_START_EVENT); + instance->DoStartCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, ACHIEV_TIMELY_DEATH_START_EVENT); } void JustDied(Unit* /*killer*/) override diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp index 2ffe06f0d75..2bf229f2b9d 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp @@ -67,7 +67,7 @@ class boss_maiden_of_grief : public CreatureScript events.ScheduleEvent(EVENT_SHOCK_OF_SORROW, urand(20000, 25000)); events.ScheduleEvent(EVENT_PILLAR_OF_WOE, urand(5000, 15000)); - instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_GOOD_GRIEF_START_EVENT); + instance->DoStopCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, ACHIEV_GOOD_GRIEF_START_EVENT); } void EnterCombat(Unit* /*who*/) override @@ -75,7 +75,7 @@ class boss_maiden_of_grief : public CreatureScript _EnterCombat(); Talk(SAY_AGGRO); - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_GOOD_GRIEF_START_EVENT); + instance->DoStartCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, ACHIEV_GOOD_GRIEF_START_EVENT); } void KilledUnit(Unit* who) override diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp index 8f30bfb20ab..0d8f9a6bce1 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp @@ -773,7 +773,7 @@ class npc_living_constellation : public CreatureScript me->DespawnOrUnsummon(1); if (InstanceScript* instance = me->GetInstanceScript()) - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, EVENT_ID_SUPERMASSIVE_START); + instance->DoStartCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, EVENT_ID_SUPERMASSIVE_START); caster->CastSpell((Unit*)NULL, SPELL_BLACK_HOLE_CREDIT, TRIGGERED_FULL_MASK); caster->ToCreature()->DespawnOrUnsummon(1); } @@ -1348,7 +1348,7 @@ class spell_algalon_supermassive_fail : public SpellScriptLoader if (!GetHitPlayer()) return; - GetHitPlayer()->ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, ACHIEVEMENT_CRITERIA_CONDITION_NO_SPELL_HIT, GetSpellInfo()->Id, true); + GetHitPlayer()->ResetCriteria(CRITERIA_TYPE_BE_SPELL_TARGET, CRITERIA_CONDITION_NO_SPELL_HIT, GetSpellInfo()->Id, true); } void Register() override diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp index cd214a0114f..c55b58367de 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp @@ -135,7 +135,7 @@ class boss_ignis : public CreatureScript if (Vehicle* _vehicle = me->GetVehicleKit()) _vehicle->RemoveAllPassengers(); - instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEVEMENT_IGNIS_START_EVENT); + instance->DoStopCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, ACHIEVEMENT_IGNIS_START_EVENT); } void EnterCombat(Unit* /*who*/) override @@ -149,7 +149,7 @@ class boss_ignis : public CreatureScript events.ScheduleEvent(EVENT_END_POT, 40000); events.ScheduleEvent(EVENT_BERSERK, 480000); Initialize(); - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEVEMENT_IGNIS_START_EVENT); + instance->DoStartCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, ACHIEVEMENT_IGNIS_START_EVENT); } void JustDied(Unit* /*killer*/) override diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp index 5acfdd8e832..b879498de74 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp @@ -196,7 +196,7 @@ class boss_kologarn : public CreatureScript if (!right && !left) events.ScheduleEvent(EVENT_STONE_SHOUT, 5000); - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, CRITERIA_DISARMED); + instance->DoStartCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, CRITERIA_DISARMED); } else { diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp index a00e0d885cd..27d05999317 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp @@ -220,7 +220,7 @@ class boss_xt002 : public CreatureScript Initialize(); - instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_MUST_DECONSTRUCT_FASTER); + instance->DoStopCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, ACHIEV_MUST_DECONSTRUCT_FASTER); } void EnterCombat(Unit* /*who*/) override @@ -234,7 +234,7 @@ class boss_xt002 : public CreatureScript //Tantrum is cast a bit slower the first time. events.ScheduleEvent(EVENT_TYMPANIC_TANTRUM, urand(TIMER_TYMPANIC_TANTRUM_MIN, TIMER_TYMPANIC_TANTRUM_MAX) * 2); - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_MUST_DECONSTRUCT_FASTER); + instance->DoStartCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, ACHIEV_MUST_DECONSTRUCT_FASTER); } void DoAction(int32 action) override diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp index 44dc40a5c1b..086e4fba780 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp @@ -485,7 +485,7 @@ class boss_voice_of_yogg_saron : public CreatureScript events.SetPhase(PHASE_ONE); instance->SetData(DATA_DRIVE_ME_CRAZY, uint32(true)); - instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); + instance->DoStopCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); Initialize(); @@ -509,7 +509,7 @@ class boss_voice_of_yogg_saron : public CreatureScript if (Creature* keeper = ObjectAccessor::GetCreature(*me, instance->GetGuidData(i))) keeper->SetInCombatWith(me); - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); + instance->DoStartCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); me->CastCustomSpell(SPELL_SUMMON_GUARDIAN_2, SPELLVALUE_MAX_TARGETS, 1); DoCast(me, SPELL_SANITY_PERIODIC); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp index 7271bd5af52..0897c7e35e8 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp @@ -660,7 +660,7 @@ class instance_ulduar : public InstanceMapScript case NPC_GUARDIAN_OF_LIFE: if (!conSpeedAtory) { - DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, CRITERIA_CON_SPEED_ATORY); + DoStartCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, CRITERIA_CON_SPEED_ATORY); conSpeedAtory = true; } break; @@ -669,7 +669,7 @@ class instance_ulduar : public InstanceMapScript case NPC_BRIGHTLEAF: if (!lumberjacked) { - DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, CRITERIA_LUMBERJACKED); + DoStartCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, CRITERIA_LUMBERJACKED); lumberjacked = true; } break; diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp index 7615217a794..358a287d485 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp @@ -213,7 +213,7 @@ public: if ((ObjectAccessor::GetCreature(*me, m_uiGraufGUID) == NULL) && !me->IsMounted()) me->SummonCreature(NPC_GRAUF, Location[0].GetPositionX(), Location[0].GetPositionY(), Location[0].GetPositionZ(), 3.0f); instance->SetBossState(DATA_SKADI_THE_RUTHLESS, NOT_STARTED); - instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); + instance->DoStopCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); } void JustReachedHome() override @@ -237,7 +237,7 @@ public: m_uiSummonTimer = 10000; me->SetInCombatWithZone(); instance->SetBossState(DATA_SKADI_THE_RUTHLESS, IN_PROGRESS); - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); + instance->DoStartCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); me->GetMotionMaster()->MoveJump(Location[0], 5.0f, 10.0f); me->SetWalk(false); m_uiMountTimer = 1000; diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index 2d253fe974d..f76f5ed9f78 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -3650,7 +3650,6 @@ Logger.sql.sql=5,Console DBErrors Logger.sql.updates=3,Console Server Logger.mmaps=3,Server -#Logger.achievement=3,Console Server #Logger.addon=3,Console Server #Logger.ahbot=3,Console Server #Logger.auctionHouse=3,Console Server @@ -3663,6 +3662,8 @@ Logger.mmaps=3,Server #Logger.cheat=3,Console Server #Logger.commands.ra=3,Console Server #Logger.condition=3,Console Server +#Logger.criteria=3,Console Server +#Logger.criteria.achievement=3,Console Server #Logger.entities.pet=3,Console Server #Logger.entities.player.character=3,Console Server #Logger.entities.player.dump=3,Console Server |