diff --git a/sql/updates/world/4.3.4/2023_10_01_01_world.sql b/sql/updates/world/4.3.4/2023_10_01_01_world.sql new file mode 100644 index 0000000000..2f96b91d84 --- /dev/null +++ b/sql/updates/world/4.3.4/2023_10_01_01_world.sql @@ -0,0 +1 @@ +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_algalon_supermassive_fail'; diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index b514d3d9ae..c761636d1d 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -21,6 +21,7 @@ #include "Battleground.h" #include "CellImpl.h" #include "ChatTextBuilder.h" +#include "Containers.h" #include "DatabaseEnv.h" #include "DBCEnums.h" #include "DisableMgr.h" @@ -44,6 +45,7 @@ #include "SpellMgr.h" #include "World.h" #include "WorldSession.h" +#include "WorldStateMgr.h" bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) { @@ -469,7 +471,7 @@ void AchievementMgr::RemoveCriteriaProgress(AchievementCriteriaEntry cons if (!entry) return; - CriteriaProgressMap::iterator criteriaProgress = m_criteriaProgress.find(entry->ID); + auto criteriaProgress = m_criteriaProgress.find(entry->ID); if (criteriaProgress == m_criteriaProgress.end()) return; @@ -497,43 +499,11 @@ void AchievementMgr::RemoveCriteriaProgress(AchievementCriteriaEntry cons SendPacket(&data); + criteriaProgress->second.counter = 0; + criteriaProgress->second.changed = true; m_criteriaProgress.erase(criteriaProgress); } -template -void AchievementMgr::ResetAchievementCriteria(AchievementCriteriaCondition condition, uint64 value, bool evenIfCriteriaComplete) -{ - TC_LOG_DEBUG("achievement", "ResetAchievementCriteria(%u, " UI64FMTD ", %u)", condition, value, evenIfCriteriaComplete); - - // disable for gamemasters with GM-mode enabled - if (GetOwner()->IsGameMaster()) - return; - - AchievementCriteriaEntryList const* achievementCriteriaList = sAchievementMgr->GetAchievementCriteriaByCondition(condition, value); - if (!achievementCriteriaList) - return; - - for (auto itr = achievementCriteriaList->begin(); itr != achievementCriteriaList->end(); ++itr) - { - AchievementCriteriaEntry const* achievementCriteria = *itr; - AchievementEntry const* achievement = sAchievementMgr->GetAchievement(achievementCriteria->ReferredAchievement); - if (!achievement) - continue; - - // don't update already completed criteria if not forced or achievement already complete - if ((IsCompletedCriteria(achievementCriteria, achievement) && !evenIfCriteriaComplete) || HasAchieved(achievement->ID)) - continue; - - RemoveCriteriaProgress(achievementCriteria); - } -} - -template<> -void AchievementMgr::ResetAchievementCriteria(AchievementCriteriaCondition /*condition*/, uint64 /*value*/, bool /*evenIfCriteriaComplete*/) -{ - // Not needed -} - template void AchievementMgr::DeleteFromDB(ObjectGuid /*guid*/) { @@ -734,7 +704,7 @@ void AchievementMgr::LoadFromDB(PreparedQueryResult achievementResult, P continue; } - if (criteria->StartTimer && time_t(date + criteria->StartTimer) < GameTime::GetGameTime()) + if (criteria->TimerTime && time_t(date + criteria->TimerTime) < GameTime::GetGameTime()) continue; CriteriaProgress& progress = m_criteriaProgress[id]; @@ -796,7 +766,7 @@ void AchievementMgr::LoadFromDB(PreparedQueryResult achievementResult, Pr continue; } - if (criteria->StartTimer && time_t(date + criteria->StartTimer) < GameTime::GetGameTime()) + if (criteria->TimerTime && time_t(date + criteria->TimerTime) < GameTime::GetGameTime()) continue; CriteriaProgress& progress = m_criteriaProgress[id]; @@ -961,7 +931,7 @@ void AchievementMgr::SendCriteriaUpdate(AchievementCriteriaEntry const* criteriaUpdate.Quantity = progress->counter; criteriaUpdate.PlayerGUID = GetOwner()->GetGUID(); criteriaUpdate.Flags = 0; - if (entry->StartTimer) + if (entry->TimerTime) criteriaUpdate.Flags = timedCompleted ? 1 : 0; // 1 is for keeping the counter at 0 in client criteriaUpdate.CurrentTime = progress->date; @@ -1179,10 +1149,10 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, for (AchievementCriteriaEntryList::const_iterator i = achievementCriteriaList.begin(); i != achievementCriteriaList.end(); ++i) { AchievementCriteriaEntry const* achievementCriteria = (*i); - AchievementEntry const* achievement = sAchievementMgr->GetAchievement(achievementCriteria->ReferredAchievement); + AchievementEntry const* achievement = sAchievementMgr->GetAchievement(achievementCriteria->AchievementID); if (!achievement) { - TC_LOG_ERROR("achievement", "UpdateAchievementCriteria: Achievement %u not found!", achievementCriteria->ReferredAchievement); + TC_LOG_ERROR("achievement", "UpdateAchievementCriteria: Achievement %u not found!", achievementCriteria->AchievementID); continue; } @@ -1619,18 +1589,18 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achi case ACHIEVEMENT_CRITERIA_TYPE_CURRENCY: case ACHIEVEMENT_CRITERIA_TYPE_CRAFT_ITEMS_GUILD: case ACHIEVEMENT_CRITERIA_TYPE_CATCH_FROM_POOL: - return progress->counter >= achievementCriteria->Amount; + return progress->counter >= achievementCriteria->Quantity; case ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA: case ACHIEVEMENT_CRITERIA_TYPE_BUY_GUILD_TABARD: case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL: return progress->counter >= 1; case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL: - return progress->counter >= achievementCriteria->Amount; + return progress->counter >= achievementCriteria->Quantity; case ACHIEVEMENT_CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS: return progress->counter >= 9000; case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA: case ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM: - return achievementCriteria->Amount && progress->counter >= achievementCriteria->Amount; + return achievementCriteria->Quantity && progress->counter >= achievementCriteria->Quantity; case ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN: return true; // handle all statistic-only criteria here @@ -1716,7 +1686,7 @@ bool AchievementMgr::IsCompletedAchievement(AchievementEntry const* entry) count += progress->counter; // for counters, field4 contains the main count requirement - if (count >= criteria->Amount) + if (count >= criteria->Quantity) return true; } return false; @@ -1762,11 +1732,6 @@ CriteriaProgress* AchievementMgr::GetCriteriaProgress(AchievementCriteriaEntr template void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* entry, uint64 changeValue, Player* referencePlayer, ProgressType ptype) { - // Don't allow to cheat - doing timed achievements without timer active - TimedAchievementMap::iterator timedIter = m_timedAchievements.find(entry->ID); - if (entry->StartTimer && timedIter == m_timedAchievements.end()) - return; - TC_LOG_DEBUG("achievement", "SetCriteriaProgress(%u, " UI64FMTD ") for (%s)", entry->ID, changeValue, GetOwner()->GetGUID().ToString().c_str()); @@ -1775,7 +1740,7 @@ void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* entr { // not create record for 0 counter but allow it for timed achievements // we will need to send 0 progress to client to start the timer - if (changeValue == 0 && !entry->StartTimer) + if (changeValue == 0 && !entry->TimerTime) return; progress = &m_criteriaProgress[entry->ID]; @@ -1802,7 +1767,7 @@ void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* entr } // not update (not mark as changed) if counter will have same value - if (progress->counter == newValue && !entry->StartTimer) + if (progress->counter == newValue && !entry->TimerTime) return; progress->counter = newValue; @@ -1810,98 +1775,102 @@ void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* entr progress->changed = true; progress->date = GameTime::GetGameTime(); // set the date to the latest update. + progress->CompletedGUID = referencePlayer ? referencePlayer->GetGUID() : ObjectGuid::Empty; - AchievementEntry const* achievement = sAchievementMgr->GetAchievement(entry->ReferredAchievement); - uint32 timeElapsed = 0; - bool criteriaComplete = IsCompletedCriteria(entry, achievement); + Seconds timeElapsed = Seconds::zero(); - if (entry->StartTimer) + if (entry->TimerTime) { - // Client expects this in packet - timeElapsed = entry->StartTimer - (timedIter->second/IN_MILLISECONDS); + auto startedItr = _startedCriteria.find(entry->ID); + if (startedItr != _startedCriteria.end()) + { + // Client expects this in packet + timeElapsed = duration_cast(Seconds(entry->TimerTime) - startedItr->second); - // Remove the timer, we wont need it anymore - if (criteriaComplete) - m_timedAchievements.erase(timedIter); + AchievementEntry const* achievement = sAchievementMgr->GetAchievement(entry->AchievementID); + bool criteriaComplete = IsCompletedCriteria(entry, achievement); + // Remove the timer, we wont need it anymore + if (criteriaComplete) + _startedCriteria.erase(startedItr); + } } - if (criteriaComplete && achievement->Flags & ACHIEVEMENT_FLAG_SHOW_CRITERIA_MEMBERS && !progress->CompletedGUID) - progress->CompletedGUID = referencePlayer->GetGUID(); - - SendCriteriaUpdate(entry, progress, timeElapsed, criteriaComplete); + SendCriteriaUpdate(entry, progress, timeElapsed.count(), true); } template -void AchievementMgr::UpdateTimedAchievements(uint32 timeDiff) +void AchievementMgr::UpdateTimedAchievementCriteria(Milliseconds timeDiff) { - if (!m_timedAchievements.empty()) + for (auto itr = _startedCriteria.begin(); itr != _startedCriteria.end();) { - for (TimedAchievementMap::iterator itr = m_timedAchievements.begin(); itr != m_timedAchievements.end();) + // Time is up, remove timer and reset progress + if (itr->second <= timeDiff) { - // Time is up, remove timer and reset progress - if (itr->second <= timeDiff) - { - AchievementCriteriaEntry const* entry = sAchievementMgr->GetAchievementCriteria(itr->first); - RemoveCriteriaProgress(entry); - m_timedAchievements.erase(itr++); - } - else - { - itr->second -= timeDiff; - ++itr; - } + AchievementCriteriaEntry const* entry = sAchievementMgr->GetAchievementCriteria(itr->first); + RemoveCriteriaProgress(entry); + itr = _startedCriteria.erase(itr); + } + else + { + itr->second -= timeDiff; + ++itr; } } } template -void AchievementMgr::StartTimedAchievement(AchievementCriteriaTimedTypes /*type*/, uint32 /*entry*/, uint32 /*timeLost = 0*/) +void AchievementMgr::StartAchievementCriteria(AchievementCriteriaStartEvent /*startEvent*/, uint32 /*entry*/, Milliseconds /*timeLost = Milliseconds::zero() */) { } template<> -void AchievementMgr::StartTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry, uint32 timeLost /* = 0 */) +void AchievementMgr::StartAchievementCriteria(AchievementCriteriaStartEvent startEvent, uint32 asset, Milliseconds timeLost /*= Milliseconds::zero()*/) { - AchievementCriteriaEntryList const& achievementCriteriaList = sAchievementMgr->GetTimedAchievementCriteriaByType(type); - for (AchievementCriteriaEntryList::const_iterator i = achievementCriteriaList.begin(); i != achievementCriteriaList.end(); ++i) + AchievementCriteriaEntryList const* criteriaList = sAchievementMgr->GetAchievementCriteriaByStartEvent(startEvent, asset); + if (!criteriaList) + return; + + for (AchievementCriteriaEntry const* criteria : *criteriaList) { - if ((*i)->StartAsset != entry) + Milliseconds timeLimit = Milliseconds::max(); // this value is for criteria that have a start event requirement but no time limit + if (criteria->TimerTime) + timeLimit = Seconds(criteria->TimerTime); + + timeLimit -= timeLost; + + if (timeLimit <= Milliseconds::zero()) continue; - AchievementEntry const* achievement = sAchievementMgr->GetAchievement((*i)->ReferredAchievement); - if (m_timedAchievements.find((*i)->ID) == m_timedAchievements.end() && !IsCompletedCriteria(*i, achievement)) - { - // Start the timer - if ((*i)->StartTimer * IN_MILLISECONDS > timeLost) - { - m_timedAchievements[(*i)->ID] = (*i)->StartTimer * IN_MILLISECONDS - timeLost; + AchievementEntry const* achievement = sAchievementMgr->GetAchievement(criteria->AchievementID); + bool canStart = !IsCompletedCriteria(criteria, achievement); - // and at client too - SetCriteriaProgress(*i, 0, GetOwner(), PROGRESS_SET); - } + if (!canStart) + continue; + + auto [itr, isNew] = _startedCriteria.try_emplace(criteria->ID, timeLimit); + if (!isNew) + { + if (!(criteria->Flags & ACHIEVEMENT_CRITERIA_FLAG_HIDDEN)) + continue; + + itr->second = timeLimit; } + + SetCriteriaProgress(criteria, 0, GetOwner(), PROGRESS_SET); } } template -void AchievementMgr::RemoveTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry) +void AchievementMgr::FailAchievementCriteria(AchievementCriteriaFailEvent failEvent, uint32 asset) { - AchievementCriteriaEntryList const& achievementCriteriaList = sAchievementMgr->GetTimedAchievementCriteriaByType(type); - for (AchievementCriteriaEntryList::const_iterator i = achievementCriteriaList.begin(); i != achievementCriteriaList.end(); ++i) + AchievementCriteriaEntryList const* criteriaList = sAchievementMgr->GetAchievementCriteriaByFailEvent(failEvent, asset); + if (!criteriaList) + return; + + for (AchievementCriteriaEntry const* criteria : *criteriaList) { - if ((*i)->StartAsset != entry) - continue; - - TimedAchievementMap::iterator timedIter = m_timedAchievements.find((*i)->ID); - // We don't have timer for this achievement - if (timedIter == m_timedAchievements.end()) - continue; - - // remove progress - RemoveCriteriaProgress(*i); - - // Remove the timer - m_timedAchievements.erase(timedIter); + _startedCriteria.erase(criteria->ID); + RemoveCriteriaProgress(criteria); } } @@ -2360,13 +2329,6 @@ bool AchievementMgr::CanUpdateCriteria(AchievementCriteriaEntry const* criter return false; } - if (achievement->MapID != -1 && referencePlayer->GetMapId() != uint32(achievement->MapID)) - { - TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: %u Type %s Achievement %u) Wrong map", - criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->Type), achievement->ID); - return false; - } - if ((achievement->Faction == ACHIEVEMENT_FACTION_HORDE && referencePlayer->GetTeam() != HORDE) || (achievement->Faction == ACHIEVEMENT_FACTION_ALLIANCE && referencePlayer->GetTeam() != ALLIANCE)) { @@ -2403,36 +2365,18 @@ bool AchievementMgr::CanUpdateCriteria(AchievementCriteriaEntry const* criter return false; } + if (criteria->RequiredWorldStateID != 0) + if (sWorldStateMgr->GetValue(criteria->RequiredWorldStateID, referencePlayer->GetMap()) != criteria->RequiredWorldStateValue) + return false; + return true; } template -bool AchievementMgr::ConditionsSatisfied(AchievementCriteriaEntry const* criteria, Player* referencePlayer) const +bool AchievementMgr::ConditionsSatisfied(AchievementCriteriaEntry const* criteria, Player* /*referencePlayer*/) const { - for (uint32 i = 0; i < MAX_CRITERIA_REQUIREMENTS; ++i) - { - if (!criteria->AdditionalRequirements[i].Type) - continue; - - switch (criteria->AdditionalRequirements[i].Type) - { - case ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP: - if (referencePlayer->GetMapId() != criteria->AdditionalRequirements[i].Asset) - return false; - break; - case ACHIEVEMENT_CRITERIA_CONDITION_NOT_IN_GROUP: - if (referencePlayer->GetGroup()) - return false; - break; - default: - break; - } - } - - if (criteria->RequiredWorldStateID != 0) - if (Map* map = referencePlayer->GetMap()) - if (map->GetWorldStateValue(criteria->RequiredWorldStateID) != criteria->RequiredWorldStateValue) - return false; + if (criteria->StartEvent && !_startedCriteria.contains(criteria->ID)) + return false; return true; } @@ -2548,7 +2492,7 @@ bool AchievementMgr::RequirementsSatisfied(AchievementCriteriaEntry const* ac bool notfit = false; for (int j = 0; j < MAX_ARENA_SLOT; ++j) { - if (achievIdByArenaSlot[j] == achievementCriteria->ReferredAchievement) + if (achievIdByArenaSlot[j] == achievementCriteria->AchievementID) { Battleground* bg = referencePlayer->GetBattleground(); if (!bg || !bg->isArena() || ArenaTeam::GetSlotByType(bg->GetArenaType()) != j) @@ -2573,7 +2517,7 @@ bool AchievementMgr::RequirementsSatisfied(AchievementCriteriaEntry const* ac bool found = false; for (int j = 0; achievIdForDungeon[j][0]; ++j) { - if (achievIdForDungeon[j][0] == achievementCriteria->ReferredAchievement) + if (achievIdForDungeon[j][0] == achievementCriteria->AchievementID) { if (map->IsRaid()) { @@ -2736,9 +2680,9 @@ bool AchievementMgr::RequirementsSatisfied(AchievementCriteriaEntry const* ac if (!miscValue1) return false; - if (achievementCriteria->AdditionalRequirements[0].Type == ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP) + if (AchievementCriteriaFailEvent(achievementCriteria->FailEvent) == AchievementCriteriaFailEvent::LeaveBattleground) { - if (referencePlayer->GetMapId() != achievementCriteria->AdditionalRequirements[0].Asset) + if (!referencePlayer->InBattleground()) return false; // map specific case (BG in fact) expected player targeted damage/heal @@ -2979,7 +2923,7 @@ bool AchievementMgr::AdditionalRequirementsSatisfied(AchievementCriteriaEntry } case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_COMPLETE_QUEST_NOT_IN_GROUP: // 35 { - if (referencePlayer->IsInGroup()) + if (referencePlayer->GetGroup()) return false; break; } @@ -3377,6 +3321,16 @@ AchievementCriteriaEntryList const& AchievementGlobalMgr::GetAchievementCriteria } } +AchievementCriteriaEntryList const* AchievementGlobalMgr::GetAchievementCriteriaByStartEvent(AchievementCriteriaStartEvent startEvent, int32 asset) const +{ + return Trinity::Containers::MapGetValuePtr(_criteriasByStartEvent[size_t(startEvent)], asset); +} + +AchievementCriteriaEntryList const* AchievementGlobalMgr::GetAchievementCriteriaByFailEvent(AchievementCriteriaFailEvent startEvent, int32 asset) const +{ + return Trinity::Containers::MapGetValuePtr(_criteriasByFailEvent[size_t(startEvent)], asset); +} + bool AchievementGlobalMgr::IsRealmCompleted(AchievementEntry const* achievement) const { auto itr = _allCompletedAchievements.find(achievement->ID); @@ -3406,6 +3360,21 @@ void AchievementGlobalMgr::SetRealmCompleted(AchievementEntry const* achievement _allCompletedAchievements[achievement->ID] = GameTime::GetGameTimeSystemPoint(); } +inline AchievementCriteriaStartEvent ToStartEvent(uint32 timedStartEvent) +{ + switch (static_cast(timedStartEvent)) + { + case AchievementCriteriaTimerStartEvent::SendEvent: return AchievementCriteriaStartEvent::SendEvent; + case AchievementCriteriaTimerStartEvent::AcceptQuest: return AchievementCriteriaStartEvent::AcceptQuest; + case AchievementCriteriaTimerStartEvent::CastSpell: return AchievementCriteriaStartEvent::CastSpell; + case AchievementCriteriaTimerStartEvent::GainAura: return AchievementCriteriaStartEvent::GainAura; + case AchievementCriteriaTimerStartEvent::KillNPC: return AchievementCriteriaStartEvent::KillNPC; + case AchievementCriteriaTimerStartEvent::UseItem: return AchievementCriteriaStartEvent::UseItem; + default: + return AchievementCriteriaStartEvent::None; + } +} + //========================================================== void AchievementGlobalMgr::LoadAchievementCriteriaList() { @@ -3428,9 +3397,9 @@ void AchievementGlobalMgr::LoadAchievementCriteriaList() ASSERT(criteria->Type < ACHIEVEMENT_CRITERIA_TYPE_TOTAL, "ACHIEVEMENT_CRITERIA_TYPE_TOTAL must be greater than or equal to %u but is currently equal to %u", criteria->Type + 1, ACHIEVEMENT_CRITERIA_TYPE_TOTAL); - AchievementEntry const* achievement = sAchievementMgr->GetAchievement(criteria->ReferredAchievement); + AchievementEntry const* achievement = sAchievementMgr->GetAchievement(criteria->AchievementID); - m_AchievementCriteriaListByAchievement[criteria->ReferredAchievement].push_back(criteria); + m_AchievementCriteriaListByAchievement[criteria->AchievementID].push_back(criteria); bool guild = false; if (achievement && achievement->Flags & ACHIEVEMENT_FLAG_GUILD) @@ -3466,27 +3435,19 @@ void AchievementGlobalMgr::LoadAchievementCriteriaList() } } - for (uint32 i = 0; i < MAX_CRITERIA_REQUIREMENTS; ++i) - { - if (criteria->AdditionalRequirements[i].Type != ACHIEVEMENT_CRITERIA_CONDITION_NONE) - { - ASSERT(criteria->AdditionalRequirements[i].Type < ACHIEVEMENT_CRITERIA_CONDITION_MAX, - "ACHIEVEMENT_CRITERIA_CONDITION_MAX must be greater than or equal to %u but is currently equal to %u", - criteria->AdditionalRequirements[i].Type + 1, ACHIEVEMENT_CRITERIA_CONDITION_MAX); + if (criteria->StartEvent) + _criteriasByStartEvent[criteria->StartEvent][criteria->StartAsset].push_back(criteria); - if (i == 0 - || criteria->AdditionalRequirements[i].Type != criteria->AdditionalRequirements[i - 1].Type - || criteria->AdditionalRequirements[i].Asset != criteria->AdditionalRequirements[i - 1].Asset) - m_AchievementCriteriasByCondition[criteria->AdditionalRequirements[i].Type][criteria->AdditionalRequirements[i].Asset].push_back(criteria); - } + // Timed criterias use a own event definition which is name-identical with StartEvent so we translate it and add the criterias to the StartEvent container + if (criteria->TimerStartEvent) + { + AchievementCriteriaStartEvent startEvent = ToStartEvent(criteria->TimerStartEvent); + if (startEvent != AchievementCriteriaStartEvent::None) + _criteriasByStartEvent[AsUnderlyingType(startEvent)][criteria->TimerAsset].push_back(criteria); } - if (criteria->StartTimer) - { - ASSERT(criteria->StartEvent < ACHIEVEMENT_TIMED_TYPE_MAX, "ACHIEVEMENT_TIMED_TYPE_MAX must be greater than or equal to %u but is currently equal to %u", - criteria->StartEvent + 1, ACHIEVEMENT_TIMED_TYPE_MAX); - m_AchievementCriteriasByTimedType[criteria->StartEvent].push_back(criteria); - } + if (criteria->FailEvent) + _criteriasByFailEvent[criteria->FailEvent][criteria->FailAsset].push_back(criteria); } TC_LOG_INFO("server.loading", ">> Loaded %u achievement criteria and %u guild achievement crieteria in %u ms.", criterias, guildCriterias, GetMSTimeDiffToNow(oldMSTime)); diff --git a/src/server/game/Achievements/AchievementMgr.h b/src/server/game/Achievements/AchievementMgr.h index 272824b492..faab7fb528 100644 --- a/src/server/game/Achievements/AchievementMgr.h +++ b/src/server/game/Achievements/AchievementMgr.h @@ -36,7 +36,6 @@ typedef std::vector AchievementEntryList; typedef std::unordered_map AchievementCriteriaListByAchievement; typedef std::unordered_map AchievementCriteriaListByMiscValue; -typedef std::unordered_map AchievementCriteriaListByCondition; typedef std::unordered_map AchievementListByReferencedId; struct CriteriaProgress @@ -266,7 +265,6 @@ class TC_GAME_API AchievementMgr static void DeleteFromDB(ObjectGuid lowguid); void LoadFromDB(PreparedQueryResult achievementResult, PreparedQueryResult criteriaResult); void SaveToDB(CharacterDatabaseTransaction& trans); - void ResetAchievementCriteria(AchievementCriteriaCondition condition, uint64 value, bool evenIfCriteriaComplete); void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1 = 0, uint64 miscValue2 = 0, uint64 miscValue3 = 0, WorldObject const* ref = nullptr, Player* referencePlayer = nullptr, GameObject* go = nullptr); void CompletedAchievement(AchievementEntry const* entry, Player* referencePlayer); void CheckAllAchievementCriteria(Player* referencePlayer); @@ -277,9 +275,9 @@ class TC_GAME_API AchievementMgr CompletedAchievementData* GetCompletedDataForAchievement(uint32 achievementId); 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 + void UpdateTimedAchievementCriteria(Milliseconds timeDiff); + void StartAchievementCriteria(AchievementCriteriaStartEvent startEvent, uint32 asset, Milliseconds timeLost = Milliseconds::zero()); + void FailAchievementCriteria(AchievementCriteriaFailEvent failEvent, uint32 asset); uint32 GetAchievementPoints() const { return _achievementPoints; } private: @@ -301,9 +299,9 @@ class TC_GAME_API AchievementMgr T* _owner; CriteriaProgressMap m_criteriaProgress; CompletedAchievementMap m_completedAchievements; - typedef std::map TimedAchievementMap; - TimedAchievementMap m_timedAchievements; // Criteria id/time left in MS uint32 _achievementPoints; + + std::unordered_map _startedCriteria; }; class TC_GAME_API AchievementGlobalMgr @@ -319,16 +317,9 @@ class TC_GAME_API AchievementGlobalMgr AchievementCriteriaEntryList const& GetAchievementCriteriaByType(AchievementCriteriaTypes type, uint32 miscValue, bool guild = false) const; - AchievementCriteriaEntryList const& GetTimedAchievementCriteriaByType(AchievementCriteriaTimedTypes type) const - { - return m_AchievementCriteriasByTimedType[type]; - } + AchievementCriteriaEntryList const* GetAchievementCriteriaByStartEvent(AchievementCriteriaStartEvent startEvent, int32 asset) const; - AchievementCriteriaEntryList const* GetAchievementCriteriaByCondition(AchievementCriteriaCondition condition, uint32 val) - { - AchievementCriteriaListByCondition::const_iterator itr = m_AchievementCriteriasByCondition[condition].find(val); - return itr != m_AchievementCriteriasByCondition[condition].end() ? &itr->second : nullptr; - } + AchievementCriteriaEntryList const* GetAchievementCriteriaByFailEvent(AchievementCriteriaFailEvent startEvent, int32 asset) const; AchievementCriteriaEntryList const* GetAchievementCriteriaByAchievement(uint32 id) const { @@ -399,9 +390,8 @@ class TC_GAME_API AchievementGlobalMgr AchievementCriteriaListByMiscValue m_AchievementCriteriasByMiscValue[ACHIEVEMENT_CRITERIA_TYPE_TOTAL]; AchievementCriteriaListByMiscValue m_GuildAchievementCriteriasByMiscValue[ACHIEVEMENT_CRITERIA_TYPE_TOTAL]; - AchievementCriteriaEntryList m_AchievementCriteriasByTimedType[ACHIEVEMENT_TIMED_TYPE_MAX]; - - AchievementCriteriaListByCondition m_AchievementCriteriasByCondition[ACHIEVEMENT_CRITERIA_CONDITION_MAX]; + std::unordered_map _criteriasByStartEvent[size_t(AchievementCriteriaStartEvent::Count)]; + std::unordered_map _criteriasByFailEvent[size_t(AchievementCriteriaFailEvent::Count)]; // store achievement criterias by achievement to speed up lookup AchievementCriteriaListByAchievement m_AchievementCriteriaListByAchievement; diff --git a/src/server/game/Battlegrounds/Arena.cpp b/src/server/game/Battlegrounds/Arena.cpp index 375cadffb5..d83ce58ea0 100644 --- a/src/server/game/Battlegrounds/Arena.cpp +++ b/src/server/game/Battlegrounds/Arena.cpp @@ -309,6 +309,7 @@ void Arena::EndBattleground(uint32 winner) { // update achievement BEFORE personal rating update uint32 rating = player->GetArenaPersonalRating(winnerArenaTeam->GetSlot()); + player->StartAchievementCriteria(AchievementCriteriaStartEvent::WinRankedArenaMatchWithTeamSize, 0); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA, rating ? rating : 1); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA, GetMapId()); player->ModifyCurrency(CURRENCY_TYPE_CONQUEST_META_ARENA, sWorld->getIntConfig(CONFIG_CURRENCY_CONQUEST_POINTS_ARENA_REWARD)); @@ -335,7 +336,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_CONDITION_NO_LOSE, 0); + player->FailAchievementCriteria(AchievementCriteriaFailEvent::LoseRankedArenaMatchWithTeamSize, 0); } } diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index b1cdab7683..61671b3535 100644 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -534,6 +534,10 @@ inline void Battleground::_ProcessJoin(uint32 diff) SetStatus(STATUS_IN_PROGRESS); SetStartDelayTime(StartDelayTimes[BG_STARTING_EVENT_FOURTH]); + for (auto const& [guid, _] : GetPlayers()) + if (Player* player = ObjectAccessor::GetPlayer(GetBgMap(), guid)) + player->StartAchievementCriteria(AchievementCriteriaStartEvent::StartBattleground, GetBgMap()->GetId()); + // Remove preparation if (isArena()) { @@ -1021,7 +1025,7 @@ void Battleground::RemovePlayerAtLeave(ObjectGuid guid, bool Transport, bool Sen player->SetBGTeam(0); // remove all criterias on bg leave - player->ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP, GetMapId(), true); + player->FailAchievementCriteria(AchievementCriteriaFailEvent::LeaveBattleground, 0); player->RemoveBattlegroundQueueJoinTime(bgTypeId); @@ -1141,9 +1145,6 @@ void Battleground::AddPlayer(Player* player) } } - // reset all map criterias on map enter - player->ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP, GetMapId(), true); - // setup BG group membership PlayerAddedToBGCheckIfBGIsRunning(player); AddOrSetPlayerToCorrectBgGroup(player, team); diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundTP.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundTP.cpp index 0e89216ea7..beec8c6a22 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundTP.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundTP.cpp @@ -567,7 +567,7 @@ void BattlegroundTP::EventPlayerClickedOnFlag(Player* player, GameObject* target UpdateFlagState(HORDE, BG_TP_FLAG_STATE_ON_PLAYER); UpdateWorldState(BG_TP_FLAG_UNK_ALLIANCE, 1); player->CastSpell(player, BG_TP_SPELL_ALLIANCE_FLAG, true); - player->StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_SPELL_TARGET, BG_TP_SPELL_ALLIANCE_FLAG_PICKED); + player->StartAchievementCriteria(AchievementCriteriaStartEvent::BeSpellTarget, BG_TP_SPELL_ALLIANCE_FLAG_PICKED); if (_flagState[1] == BG_TP_FLAG_STATE_ON_PLAYER) _bothFlagsKept = true; } @@ -585,7 +585,7 @@ void BattlegroundTP::EventPlayerClickedOnFlag(Player* player, GameObject* target UpdateFlagState(ALLIANCE, BG_TP_FLAG_STATE_ON_PLAYER); UpdateWorldState(BG_TP_FLAG_UNK_HORDE, 1); player->CastSpell(player, BG_TP_SPELL_HORDE_FLAG, true); - player->StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_SPELL_TARGET, BG_TP_SPELL_HORDE_FLAG_PICKED); + player->StartAchievementCriteria(AchievementCriteriaStartEvent::BeSpellTarget, BG_TP_SPELL_HORDE_FLAG_PICKED); if (_flagState[0] == BG_TP_FLAG_STATE_ON_PLAYER) _bothFlagsKept = true; } diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp index 2cc669e278..6509f92618 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp @@ -464,7 +464,7 @@ void BattlegroundWS::EventPlayerClickedOnFlag(Player* player, GameObject* target //update world state to show correct flag carrier UpdateFlagState(HORDE, BG_WS_FLAG_STATE_ON_PLAYER); player->CastSpell(player, BG_WS_SPELL_SILVERWING_FLAG, true); - player->StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_SPELL_TARGET, BG_WS_SPELL_SILVERWING_FLAG_PICKED); + player->StartAchievementCriteria(AchievementCriteriaStartEvent::BeSpellTarget, BG_WS_SPELL_SILVERWING_FLAG_PICKED); if (_flagState[1] == BG_WS_FLAG_STATE_ON_PLAYER) _bothFlagsKept = true; } @@ -481,7 +481,7 @@ void BattlegroundWS::EventPlayerClickedOnFlag(Player* player, GameObject* target //update world state to show correct flag carrier UpdateFlagState(ALLIANCE, BG_WS_FLAG_STATE_ON_PLAYER); player->CastSpell(player, BG_WS_SPELL_WARSONG_FLAG, true); - player->StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_SPELL_TARGET, BG_WS_SPELL_WARSONG_FLAG_PICKED); + player->StartAchievementCriteria(AchievementCriteriaStartEvent::BeSpellTarget, BG_WS_SPELL_WARSONG_FLAG_PICKED); if (_flagState[0] == BG_WS_FLAG_STATE_ON_PLAYER) _bothFlagsKept = true; } diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index fe169c7741..6f8f6344e0 100644 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -100,26 +100,9 @@ enum AchievementFlags enum AchievementCriteriaLimits { - MAX_CRITERIA_REQUIREMENTS = 2, MAX_ADDITIONAL_CRITERIA_CONDITIONS = 3 }; -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 - - ACHIEVEMENT_CRITERIA_CONDITION_MAX -}; - enum AchievementCriteriaAdditionalCondition { ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_DRUNK_VALUE = 1, @@ -180,17 +163,57 @@ enum AchievementCriteriaFlags ACHIEVEMENT_CRITERIA_FLAG_MONEY_COUNTER = 0x00000020 // Displays counter as money }; -enum AchievementCriteriaTimedTypes : uint8 +enum class AchievementCriteriaFailEvent : uint8 { - 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 + None = 0, + Death = 1, // Death + Hours24WithoutCompletingDailyQuest = 2, // 24 hours without completing a daily quest + LeaveBattleground = 3, // Leave a battleground + LoseRankedArenaMatchWithTeamSize = 4, // Lose a ranked arena match with team size {#Team Size} + LoseAura = 5, // Lose aura "{Spell}" + GainAura = 6, // Gain aura "{Spell}" + GainAuraEffect = 7, // Gain aura effect "{SpellAuraNames.EnumID}" + CastSpell = 8, // Cast spell "{Spell}" + BeSpellTarget = 9, // Have spell "{Spell}" cast on you + ModifyPartyStatus = 10, // Modify your party status - ACHIEVEMENT_TIMED_TYPE_MAX + Count +}; + +enum class AchievementCriteriaStartEvent : uint8 +{ + None = 0, // - NONE - + ReachLevel = 1, // Reach level {#Level} + CompleteDailyQuest = 2, // Complete daily quest "{QuestV2}" + StartBattleground = 3, // Start battleground "{Map}" + WinRankedArenaMatchWithTeamSize = 4, // Win a ranked arena match with team size {#Team Size} + GainAura = 5, // Gain aura "{Spell}" + GainAuraEffect = 6, // Gain aura effect "{SpellAuraNames.EnumID}" + CastSpell = 7, // Cast spell "{Spell}" + BeSpellTarget = 8, // Have spell "{Spell}" cast on you + AcceptQuest = 9, // Accept quest "{QuestV2}" + KillNPC = 10, // Kill NPC "{Creature}" + KillPlayer = 11, // Kill player + UseItem = 12, // Use item "{Item}" + SendEvent = 13, // Send event "{GameEvents}" (player-sent/instance only) + + Count +}; + +enum class AchievementCriteriaTimerStartEvent : uint8 +{ + None = 0, + SendEvent = 1, + AcceptQuest = 2, + Unused3 = 3, + Unused4 = 4, + CastSpell = 5, + GainAura = 6, + KillNPC = 7, + Unused8 = 8, + UseItem = 9, + + Count }; enum AchievementCriteriaTypes : uint8 diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index 7d76d67c58..361a4dcbaf 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -58,7 +58,7 @@ struct AchievementCategoryEntry struct AchievementCriteriaEntry { uint32 ID; // 0 - uint32 ReferredAchievement; // 1 + uint32 AchievementID; // 1 uint32 Type; // 2 union @@ -164,25 +164,19 @@ struct AchievementCriteriaEntry // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE_TYPE = 138 uint32 GuildChallengeType; - } Asset; - - uint64 Amount; - - struct - { - uint32 Type; - uint32 Asset; - } AdditionalRequirements[MAX_CRITERIA_REQUIREMENTS]; + } Asset; // 3 + uint64 Quantity; // 4 + uint32 StartEvent; // 5 + int32 StartAsset; // 6 + uint32 FailEvent; // 7 + int32 FailAsset; // 8 char* Description; // 9 - uint32 Flags; // 10 - uint32 StartEvent; // 11 Only appears with timed achievements, seems to be the type of starting a timed Achievement, only type 1 and some of type 6 need manual starting - // 1: ByEventId(?) (serverside IDs), 2: ByQuestId, 5: ByCastSpellId(?) - // 6: BySpellIdTarget(some of these are unknown spells, some not, some maybe spells) - // 7: ByKillNpcId, 9: ByUseItemId - uint32 StartAsset; // 12 Alway appears with timed events, used internally to start the achievement, store - uint32 StartTimer; // 13 time limit in seconds - uint32 OrderIndex; // 14 also used in achievement shift-links as index in state bitmask + uint32 Flags; // 10 + uint32 TimerStartEvent; // 11 + uint32 TimerAsset; // 12 + uint32 TimerTime; // 13 + uint32 OrderIndex; // 14 uint32 RequiredWorldStateID; // 15 int32 RequiredWorldStateValue; // 16 uint32 AdditionalConditionType[MAX_ADDITIONAL_CRITERIA_CONDITIONS]; // 17-19 diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 73242bf195..0fefd12456 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -1031,7 +1031,7 @@ void Player::Update(uint32 p_time) } } - m_achievementMgr->UpdateTimedAchievements(p_time); + m_achievementMgr->UpdateTimedAchievementCriteria(Milliseconds(p_time)); if (HasUnitState(UNIT_STATE_MELEE_ATTACKING) && !HasUnitState(UNIT_STATE_CASTING)) { @@ -1350,7 +1350,7 @@ void Player::setDeathState(DeathState s) UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON, 1); // reset all death criterias - ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_CONDITION_NO_DEATH, 0); + FailAchievementCriteria(AchievementCriteriaFailEvent::Death, 0); } Unit::setDeathState(s); @@ -2340,6 +2340,7 @@ void Player::GiveLevel(uint8 level) CharacterDatabase.CommitTransaction(trans); } + StartAchievementCriteria(AchievementCriteriaStartEvent::ReachLevel, level); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL); // Refer-A-Friend @@ -14188,7 +14189,7 @@ void Player::AddQuest(Quest const* quest, Object* questGiver) m_QuestStatusSave[quest_id] = QUEST_DEFAULT_SAVE_TYPE; - StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_QUEST, quest_id); + StartAchievementCriteria(AchievementCriteriaStartEvent::AcceptQuest, quest_id); SendQuestUpdate(quest_id); @@ -14409,6 +14410,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, SetDailyQuestStatus(quest_id); if (quest->IsDaily()) { + StartAchievementCriteria(AchievementCriteriaStartEvent::CompleteDailyQuest, 0); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST, quest_id); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY, quest_id); } @@ -15653,7 +15655,7 @@ void Player::KilledMonsterCredit(uint32 entry, ObjectGuid guid /*= ObjectGuid::E real_entry = killed->GetEntry(); } - StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_CREATURE, real_entry); // MUST BE CALLED FIRST + StartAchievementCriteria(AchievementCriteriaStartEvent::KillNPC, real_entry); // MUST BE CALLED FIRST UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, real_entry, addkillcount, 0, killed); for (uint8 i = 0; i < MAX_QUEST_LOG_SIZE; ++i) @@ -15709,6 +15711,7 @@ void Player::KilledMonsterCredit(uint32 entry, ObjectGuid guid /*= ObjectGuid::E void Player::KilledPlayerCredit(uint16 count) { + StartAchievementCriteria(AchievementCriteriaStartEvent::KillPlayer, 0); for (uint8 i = 0; i < MAX_QUEST_LOG_SIZE; ++i) { uint32 questid = GetQuestSlotQuestId(i); @@ -23357,7 +23360,6 @@ void Player::ResetWeeklyQuestStatus() m_weeklyquests.clear(); // DB data deleted in caller m_WeeklyQuestChanged = false; - } void Player::ResetSeasonalQuestStatus(uint16 event_id, time_t eventStartTime) @@ -25319,19 +25321,14 @@ bool Player::HasAchieved(uint32 achievementId) const return m_achievementMgr->HasAchieved(achievementId); } -void Player::StartTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry, uint32 timeLost/* = 0*/) +void Player::StartAchievementCriteria(AchievementCriteriaStartEvent startEvent, uint32 entry, Milliseconds timeLost/* = Milliseconds::zero()*/) { - m_achievementMgr->StartTimedAchievement(type, entry, timeLost); + m_achievementMgr->StartAchievementCriteria(startEvent, entry, timeLost); } -void Player::RemoveTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry) +void Player::FailAchievementCriteria(AchievementCriteriaFailEvent failEvent, int32 failAsset) { - m_achievementMgr->RemoveTimedAchievement(type, entry); -} - -void Player::ResetAchievementCriteria(AchievementCriteriaCondition condition, uint64 value, bool evenIfCriteriaComplete /* = false*/) -{ - m_achievementMgr->ResetAchievementCriteria(condition, value, evenIfCriteriaComplete); + m_achievementMgr->FailAchievementCriteria(failEvent, failAsset); } void Player::UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1 /*= 0*/, uint64 miscValue2 /*= 0*/, uint64 miscValue3 /*= 0*/, WorldObject* ref /*= nullptr*/, GameObject* go /*= nullptr*/) diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 1f117b54ec..156ba5c4ba 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2324,10 +2324,9 @@ class TC_GAME_API Player : public Unit, public GridObject uint32 GetAchievementPoints() const; bool HasAchieved(uint32 achievementId) const; void ResetAchievements(); - void ResetAchievementCriteria(AchievementCriteriaCondition condition, uint64 value, bool evenIfCriteriaComplete = false); + void FailAchievementCriteria(AchievementCriteriaFailEvent condition, int32 failAsset); void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1 = 0, uint64 miscValue2 = 0, uint64 miscValue3 = 0, WorldObject* ref = nullptr, GameObject* go = nullptr); - void StartTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry, uint32 timeLost = 0); - void RemoveTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry); + void StartAchievementCriteria(AchievementCriteriaStartEvent startEvent, uint32 entry, Milliseconds timeLost = Milliseconds::zero()); void CompletedAchievement(AchievementEntry const* entry); bool HasTitle(uint32 bitIndex) const; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 3201190a91..ae0da6495e 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -3167,8 +3167,14 @@ void Unit::_ApplyAura(AuraApplication* aurApp, uint8 effMask) } if (Player* player = ToPlayer()) + { if (sConditionMgr->IsSpellUsedInSpellClickConditions(aurApp->GetBase()->GetId())) player->UpdateVisibleGameobjectsOrSpellClicks(); + + player->FailAchievementCriteria(AchievementCriteriaFailEvent::GainAura, aurApp->GetBase()->GetId()); + player->StartAchievementCriteria(AchievementCriteriaStartEvent::GainAura, aurApp->GetBase()->GetId()); + player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2, aurApp->GetBase()->GetId()); + } } // removes aura application from lists and unapplies effects @@ -3246,9 +3252,13 @@ void Unit::_UnapplyAura(AuraApplicationMap::iterator& i, AuraRemoveFlags removeM aura->HandleAuraSpecificMods(aurApp, caster, false, false); if (Player* player = ToPlayer()) + { if (sConditionMgr->IsSpellUsedInSpellClickConditions(aurApp->GetBase()->GetId())) player->UpdateVisibleGameobjectsOrSpellClicks(); + player->FailAchievementCriteria(AchievementCriteriaFailEvent::LoseAura, aurApp->GetBase()->GetId()); + } + i = m_appliedAuras.begin(); } @@ -3309,7 +3319,14 @@ void Unit::_RemoveNoStackAurasDueToAura(Aura* aura) void Unit::_RegisterAuraEffect(AuraEffect* aurEff, bool apply) { if (apply) + { m_modAuras[aurEff->GetAuraType()].push_back(aurEff); + if (Player* player = ToPlayer()) + { + player->StartAchievementCriteria(AchievementCriteriaStartEvent::GainAuraEffect, aurEff->GetAuraType()); + player->FailAchievementCriteria(AchievementCriteriaFailEvent::GainAuraEffect, aurEff->GetAuraType()); + } + } else m_modAuras[aurEff->GetAuraType()].remove(aurEff); } diff --git a/src/server/game/Events/GameEventSender.cpp b/src/server/game/Events/GameEventSender.cpp index cd150a21d3..77b0cc87ef 100644 --- a/src/server/game/Events/GameEventSender.cpp +++ b/src/server/game/Events/GameEventSender.cpp @@ -56,7 +56,7 @@ void GameEvents::TriggerForPlayer(uint32 gameEventId, Player* source) { Map* map = source->GetMap(); if (map->Instanceable()) - source->StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, gameEventId); + source->StartAchievementCriteria(AchievementCriteriaStartEvent::SendEvent, gameEventId); } void GameEvents::TriggerForMap(uint32 gameEventId, Map* map, WorldObject* source, WorldObject* target) diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 60dc6a125f..1076330b7b 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -499,6 +499,8 @@ bool Group::AddMember(Player* player) if (isRaidGroup()) player->UpdateVisibleGameobjectsOrSpellClicks(); + player->FailAchievementCriteria(AchievementCriteriaFailEvent::ModifyPartyStatus, 0); + { // Broadcast new player group member fields to rest of the group player->SetFieldNotifyFlag(UF_FLAG_PARTY_MEMBER); @@ -579,6 +581,9 @@ bool Group::RemoveMember(ObjectGuid guid, const RemoveMethod& method /*= GROUP_R if (isLFGGroup() && method == GROUP_REMOVEMETHOD_KICK) return !m_memberSlots.empty(); + if (player) + player->FailAchievementCriteria(AchievementCriteriaFailEvent::ModifyPartyStatus, 0); + // remove member and change leader (if need) only if strong more 2 members _before_ member remove (BG/BF allow 1 member group) if (GetMembersCount() > ((isBGGroup() || isLFGGroup() || isBFGroup()) ? 1u : 2u)) { diff --git a/src/server/game/Handlers/QuestHandler.cpp b/src/server/game/Handlers/QuestHandler.cpp index 4cc00d61ed..24dbd016bb 100644 --- a/src/server/game/Handlers/QuestHandler.cpp +++ b/src/server/game/Handlers/QuestHandler.cpp @@ -409,7 +409,6 @@ void WorldSession::HandleQuestLogRemoveQuest(WorldPackets::Quest::QuestLogRemove _player->TakeQuestSourceItem(questId, true); // remove quest src item from player _player->AbandonQuest(questId); // remove all quest items player received before abandoning quest. Note, this does not remove normal drop items that happen to be quest requirements. _player->RemoveActiveQuest(questId); - _player->RemoveTimedAchievement(ACHIEVEMENT_TIMED_TYPE_QUEST, questId); TC_LOG_INFO("network", "Player %u abandoned quest %u", _player->GetGUID().GetCounter(), questId); diff --git a/src/server/game/Instances/InstanceScript.cpp b/src/server/game/Instances/InstanceScript.cpp index 4c318abe92..cb6fb71f82 100644 --- a/src/server/game/Instances/InstanceScript.cpp +++ b/src/server/game/Instances/InstanceScript.cpp @@ -22,6 +22,7 @@ #include "CreatureAIImpl.h" #include "DatabaseEnv.h" #include "DBCStores.h" +#include "GameEventSender.h" #include "GameObject.h" #include "Group.h" #include "Guild.h" @@ -121,6 +122,25 @@ ObjectGuid InstanceScript::GetGuidData(uint32 type) const return GetObjectGuid(type); } + +void InstanceScript::TriggerGameEvent(uint32 gameEventId, WorldObject* source /*= nullptr*/, WorldObject* target /*= nullptr*/) +{ + if (source) + { + ZoneScript::TriggerGameEvent(gameEventId, source, target); + return; + } + + ProcessEvent(target, gameEventId, source); + instance->DoOnPlayers([gameEventId](Player* player) + { + GameEvents::TriggerForPlayer(gameEventId, player); + }); + + GameEvents::TriggerForMap(gameEventId, instance); +} + + Creature* InstanceScript::GetCreature(uint32 type) { return instance->GetCreature(GetObjectGuid(type)); @@ -611,28 +631,6 @@ void InstanceScript::DoUpdateAchievementCriteria(AchievementCriteriaTypes type, player->UpdateAchievementCriteria(type, miscValue1, miscValue2, 0, unit); } -// Start timed achievement for all players in instance -void InstanceScript::DoStartTimedAchievement(AchievementCriteriaTimedTypes 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); -} - -// Stop timed achievement for all players in instance -void InstanceScript::DoStopTimedAchievement(AchievementCriteriaTimedTypes 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); -} - // Remove Auras due to Spell on all players in instance void InstanceScript::DoRemoveAurasDueToSpellOnPlayers(uint32 spell) { diff --git a/src/server/game/Instances/InstanceScript.h b/src/server/game/Instances/InstanceScript.h index 0347d0e7b7..e9405121dc 100644 --- a/src/server/game/Instances/InstanceScript.h +++ b/src/server/game/Instances/InstanceScript.h @@ -40,8 +40,8 @@ class Player; class Unit; class WorldPacket; enum AchievementCriteriaTypes : uint8; -enum AchievementCriteriaTimedTypes : uint8; enum EncounterCreditType : uint8; +enum class AchievementCriteriaStartEvent : uint8; enum EncounterFrameType { @@ -187,6 +187,10 @@ class TC_GAME_API InstanceScript : public ZoneScript ObjectGuid GetObjectGuid(uint32 type) const; virtual ObjectGuid GetGuidData(uint32 type) const override; + // Triggers a GameEvent + // * If source is nullptr then event is triggered for each player in the instance as "source" + void TriggerGameEvent(uint32 gameEventId, WorldObject* source = nullptr, WorldObject* target = nullptr) override; + Creature* GetCreature(uint32 type); GameObject* GetGameObject(uint32 type); @@ -214,10 +218,6 @@ class TC_GAME_API InstanceScript : public ZoneScript // Update Achievement Criteria for all players in instance void DoUpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscValue1 = 0, uint32 miscValue2 = 0, Unit* unit = nullptr); - // Start/Stop Timed Achievement Criteria for all players in instance - void DoStartTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry); - void DoStopTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry); - // Remove Auras due to Spell on all players in instance void DoRemoveAurasDueToSpellOnPlayers(uint32 spell); diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index e37194266c..1ce522d517 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -25,6 +25,7 @@ #include "GridDefines.h" #include "GridRefManager.h" #include "MapDefines.h" +#include "MapReference.h" #include "MapRefManager.h" #include "MPSCQueue.h" #include "ObjectGuid.h" @@ -335,6 +336,14 @@ class TC_GAME_API Map : public GridRefManager typedef MapRefManager PlayerList; PlayerList const& GetPlayers() const { return m_mapRefManager; } + template + void DoOnPlayers(T&& fn) + { + for (MapReference const& ref : GetPlayers()) + if (Player* player = ref.GetSource()) + fn(player); + } + //per-map script storage void ScriptsStart(std::map> const& scripts, uint32 id, Object* source, Object* target); void ScriptCommandStart(ScriptInfo const& script, uint32 delay, Object* source, Object* target); diff --git a/src/server/game/Maps/ZoneScript.cpp b/src/server/game/Maps/ZoneScript.cpp index 5117eee7f7..9dce551910 100644 --- a/src/server/game/Maps/ZoneScript.cpp +++ b/src/server/game/Maps/ZoneScript.cpp @@ -17,8 +17,25 @@ #include "ZoneScript.h" #include "Creature.h" +#include "GameEventSender.h" + +ZoneScript::ZoneScript() +{ +} + +ZoneScript::~ZoneScript() +{ +} uint32 ZoneScript::GetCreatureEntry(ObjectGuid::LowType /*guidLow*/, CreatureData const* data) { return data->id; } + +void ZoneScript::TriggerGameEvent(uint32 gameEventId, WorldObject* source /*= nullptr*/, WorldObject* target /*= nullptr*/) +{ + if (source) + GameEvents::Trigger(gameEventId, source, target); + else + ProcessEvent(nullptr, gameEventId, nullptr); +} diff --git a/src/server/game/Maps/ZoneScript.h b/src/server/game/Maps/ZoneScript.h index c7c28beec0..4cc0336238 100644 --- a/src/server/game/Maps/ZoneScript.h +++ b/src/server/game/Maps/ZoneScript.h @@ -30,8 +30,8 @@ struct CreatureData; class TC_GAME_API ZoneScript { public: - ZoneScript() { } - virtual ~ZoneScript() { } + ZoneScript(); + virtual ~ZoneScript(); virtual uint32 GetCreatureEntry(ObjectGuid::LowType /*guidLow*/, CreatureData const* data); virtual uint32 GetGameObjectEntry(ObjectGuid::LowType /*guidLow*/, uint32 entry) { return entry; } @@ -55,6 +55,7 @@ class TC_GAME_API ZoneScript virtual uint32 GetData(uint32 /*DataId*/) const { return 0; } virtual void SetData(uint32 /*DataId*/, uint32 /*Value*/) { } + virtual void TriggerGameEvent(uint32 gameEventId, WorldObject* source = nullptr, WorldObject* target = nullptr); virtual void ProcessEvent(WorldObject* /*obj*/, uint32 /*eventId*/, WorldObject* /*invoker*/) { } }; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 17d60efc86..02d31c3434 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -2930,16 +2930,13 @@ SpellMissInfo Spell::PreprocessSpellHit(Unit* unit, bool scaleAura, TargetInfo& if (Player* player = unit->ToPlayer()) { - player->StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_SPELL_TARGET, m_spellInfo->Id); + player->FailAchievementCriteria(AchievementCriteriaFailEvent::BeSpellTarget, m_spellInfo->Id); + player->StartAchievementCriteria(AchievementCriteriaStartEvent::BeSpellTarget, 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); } 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); - } if (m_caster != unit) { @@ -3669,10 +3666,12 @@ void Spell::_cast(bool skipCheck) { if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CAST_ITEM) && m_CastItem) { - player->StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_ITEM, m_CastItem->GetEntry()); + player->StartAchievementCriteria(AchievementCriteriaStartEvent::UseItem, m_CastItem->GetEntry()); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM, m_CastItem->GetEntry()); } + player->FailAchievementCriteria(AchievementCriteriaFailEvent::CastSpell, m_spellInfo->Id); + player->StartAchievementCriteria(AchievementCriteriaStartEvent::CastSpell, m_spellInfo->Id); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL, m_spellInfo->Id); } diff --git a/src/server/scripts/Kalimdor/HallsOfOrigination/instance_halls_of_origination.cpp b/src/server/scripts/Kalimdor/HallsOfOrigination/instance_halls_of_origination.cpp index ad260ebcd9..27c21524f0 100644 --- a/src/server/scripts/Kalimdor/HallsOfOrigination/instance_halls_of_origination.cpp +++ b/src/server/scripts/Kalimdor/HallsOfOrigination/instance_halls_of_origination.cpp @@ -303,7 +303,7 @@ class instance_halls_of_origination : public InstanceMapScript if (GameObject* door = GetGameObject(DATA_VAULT_OF_LIGHTS_ENTRANCE_DOOR)) door->SetGoState(GO_STATE_ACTIVE); - DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_VAULT_OF_LIGHTS_START_EVENT); + TriggerGameEvent(ACHIEV_VAULT_OF_LIGHTS_START_EVENT); _events.ScheduleEvent(EVENT_FAIL_VAULTS_OF_LIGHT_ACHIEVEMENT, 5min); } else if (value == DONE) diff --git a/src/server/scripts/Kalimdor/OnyxiasLair/boss_onyxia.cpp b/src/server/scripts/Kalimdor/OnyxiasLair/boss_onyxia.cpp index 8689489e57..0f6b5ab527 100644 --- a/src/server/scripts/Kalimdor/OnyxiasLair/boss_onyxia.cpp +++ b/src/server/scripts/Kalimdor/OnyxiasLair/boss_onyxia.cpp @@ -157,7 +157,6 @@ public: _Reset(); me->SetReactState(REACT_AGGRESSIVE); instance->SetData(DATA_ONYXIA_PHASE, Phase); - instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); } void JustEngagedWith(Unit* who) override @@ -168,7 +167,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->TriggerGameEvent(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 546918af8c..d6af793fa5 100644 --- a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_herald_volazj.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_herald_volazj.cpp @@ -171,7 +171,6 @@ public: Initialize(); instance->SetBossState(DATA_HERALD_VOLAZJ, NOT_STARTED); - instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_QUICK_DEMISE_START_EVENT); // Visible for all players in insanity for (uint32 i = 173; i <= 177; ++i) @@ -191,7 +190,7 @@ public: Talk(SAY_AGGRO); instance->SetBossState(DATA_HERALD_VOLAZJ, IN_PROGRESS); - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_QUICK_DEMISE_START_EVENT); + instance->TriggerGameEvent(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 db1f5cf6b2..8373b31874 100644 --- a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp @@ -122,7 +122,6 @@ public: { BossAI::Reset(); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_GOTTA_GO_START_EVENT); _nextSubmerge = 75; _petCount = 0; } @@ -139,7 +138,7 @@ public: door2->SetGoState(GO_STATE_ACTIVE); Talk(SAY_AGGRO); - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_GOTTA_GO_START_EVENT); + instance->TriggerGameEvent(ACHIEV_GOTTA_GO_START_EVENT); events.SetPhase(PHASE_EMERGE); events.ScheduleEvent(EVENT_CLOSE_DOOR, Seconds(5)); 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 5dae961039..f9f59479a2 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp @@ -370,8 +370,6 @@ class boss_fjola : public CreatureScript TwinPactSpellId = SPELL_LIGHT_TWIN_PACT; TouchSpellId = SPELL_LIGHT_TOUCH; SpikeSpellId = SPELL_LIGHT_TWIN_SPIKE; - - instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, EVENT_START_TWINS_FIGHT); boss_twin_baseAI::Reset(); } @@ -410,7 +408,7 @@ class boss_fjola : public CreatureScript void JustEngagedWith(Unit* who) override { - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, EVENT_START_TWINS_FIGHT); + instance->TriggerGameEvent(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::JustEngagedWith(who); 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 dbc75156f3..36ab549e6d 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp @@ -812,7 +812,6 @@ 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); } void JustDied(Unit* /*killer*/) override @@ -1062,7 +1061,7 @@ class npc_jaina_or_sylvanas_escape_hor : public CreatureScript } } _invincibility = false; - _instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_NOT_RETREATING_EVENT); + _instance->TriggerGameEvent(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 014b6314bb..16b7cec037 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 @@ -348,8 +348,6 @@ class instance_halls_of_reflection : public InstanceMapScript } break; case FAIL: - DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_NOT_RETREATING_EVENT); - if (Creature* jainaOrSylvanas = instance->GetCreature(JainaOrSylvanasEscapeGUID)) jainaOrSylvanas->DespawnOrUnsummon(10000); diff --git a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp index d1d023ea2c..09f466ba2b 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp @@ -148,7 +148,7 @@ public: _JustDied(); // start achievement timer (kill Maexna within 20 min) - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); + instance->TriggerGameEvent(ACHIEV_TIMED_START_EVENT); } void JustEngagedWith(Unit* who) override diff --git a/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp b/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp index e67e03cf5c..df2d188c05 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp @@ -72,8 +72,6 @@ public: void Reset() override { _Reset(); - - instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_MAKE_QUICK_WERK_OF_HIM_STARTING_EVENT); } void KilledUnit(Unit* /*Victim*/) override @@ -96,7 +94,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->TriggerGameEvent(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 8553873977..87c07410c1 100644 --- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp +++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp @@ -381,7 +381,6 @@ public: SetPhase(PHASE_NOT_STARTED, true); me->SetReactState(REACT_PASSIVE); - instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); instance->SetBossState(DATA_MALYGOS_EVENT, NOT_STARTED); } @@ -573,7 +572,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->TriggerGameEvent(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 a1d475a9c7..41c96abea8 100644 --- a/src/server/scripts/Northrend/Nexus/Oculus/boss_drakos.cpp +++ b/src/server/scripts/Northrend/Nexus/Oculus/boss_drakos.cpp @@ -138,7 +138,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->TriggerGameEvent(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 eae279557d..aa8bb660f3 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_loken.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_loken.cpp @@ -82,7 +82,7 @@ struct boss_loken : public BossAI events.ScheduleEvent(EVENT_ARC_LIGHTNING, 15s); events.ScheduleEvent(EVENT_LIGHTNING_NOVA, 20s); events.ScheduleEvent(EVENT_RESUME_PULSING_SHOCKWAVE, 1s); - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMELY_DEATH_START_EVENT); + instance->TriggerGameEvent(ACHIEV_TIMELY_DEATH_START_EVENT); me->SetStandState(UNIT_STAND_STATE_STAND); } @@ -95,7 +95,6 @@ struct boss_loken : public BossAI void EnterEvadeMode(EvadeReason /*why*/) override { - instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMELY_DEATH_START_EVENT); _DespawnAtEvade(); } 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 2b902096a4..5681d5b64b 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,8 +67,6 @@ class boss_maiden_of_grief : public CreatureScript events.ScheduleEvent(EVENT_STORM_OF_GRIEF, 10000); 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); } void JustEngagedWith(Unit* who) override @@ -76,7 +74,7 @@ class boss_maiden_of_grief : public CreatureScript BossAI::JustEngagedWith(who); Talk(SAY_AGGRO); - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_GOOD_GRIEF_START_EVENT); + instance->TriggerGameEvent(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 adfe6e2d64..4da3e9b6dd 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 @@ -787,7 +787,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->TriggerGameEvent(EVENT_ID_SUPERMASSIVE_START); caster->CastSpell((Unit*)nullptr, SPELL_BLACK_HOLE_CREDIT, TRIGGERED_FULL_MASK); caster->ToCreature()->DespawnOrUnsummon(1); } @@ -1329,33 +1329,6 @@ class spell_algalon_cosmic_smash_damage : public SpellScriptLoader } }; -class spell_algalon_supermassive_fail : public SpellScriptLoader -{ - public: - spell_algalon_supermassive_fail() : SpellScriptLoader("spell_algalon_supermassive_fail") { } - - class spell_algalon_supermassive_fail_SpellScript : public SpellScript - { - void RecalculateDamage() - { - if (!GetHitPlayer()) - return; - - GetHitPlayer()->ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_CONDITION_NO_SPELL_HIT, GetSpellInfo()->Id, true); - } - - void Register() override - { - OnHit.Register(&spell_algalon_supermassive_fail_SpellScript::RecalculateDamage); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_algalon_supermassive_fail_SpellScript(); - } -}; - void AddSC_boss_algalon_the_observer() { new boss_algalon_the_observer(); @@ -1371,5 +1344,4 @@ void AddSC_boss_algalon_the_observer() new spell_algalon_remove_phase(); new spell_algalon_cosmic_smash(); new spell_algalon_cosmic_smash_damage(); - new spell_algalon_supermassive_fail(); } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp index 7f54b1c62b..57f98f3148 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp @@ -137,8 +137,6 @@ class boss_ignis : public CreatureScript _Reset(); if (Vehicle* _vehicle = me->GetVehicleKit()) _vehicle->RemoveAllPassengers(); - - instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEVEMENT_IGNIS_START_EVENT); } void JustEngagedWith(Unit* who) override @@ -152,7 +150,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->TriggerGameEvent(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 e9fd250f64..6bce5fedea 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp @@ -200,7 +200,7 @@ class boss_kologarn : public CreatureScript if (!right && !left) events.ScheduleEvent(EVENT_STONE_SHOUT, 5000); - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, CRITERIA_DISARMED); + instance->TriggerGameEvent(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 8385c5a1ab..e648dca73e 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp @@ -203,8 +203,6 @@ class boss_xt002 : public CreatureScript DoCastSelf(SPELL_STAND); Initialize(); - - instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_MUST_DECONSTRUCT_FASTER); } void EnterEvadeMode(EvadeReason /*why*/) override @@ -224,7 +222,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->TriggerGameEvent(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 00a6087bf6..3242b582ff 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp @@ -493,7 +493,6 @@ 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); Initialize(); @@ -517,7 +516,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->TriggerGameEvent(ACHIEV_TIMED_START_EVENT); DoCastAOE(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 a1c6a0f927..a4e35a99f0 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp @@ -558,7 +558,7 @@ class instance_ulduar : public InstanceMapScript case NPC_GUARDIAN_OF_LIFE: if (!conSpeedAtory) { - DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, CRITERIA_CON_SPEED_ATORY); + TriggerGameEvent(CRITERIA_CON_SPEED_ATORY); conSpeedAtory = true; } break; @@ -567,7 +567,7 @@ class instance_ulduar : public InstanceMapScript case NPC_BRIGHTLEAF: if (!lumberjacked) { - DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, CRITERIA_LUMBERJACKED); + TriggerGameEvent(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 67cd99f98d..ea722e3ff7 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp @@ -169,8 +169,6 @@ public: me->SetReactState(REACT_PASSIVE); if (!instance->GetCreature(DATA_GRAUF)) me->SummonCreature(NPC_GRAUF, GraufLoc); - - instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_LODI_DODI_WE_LOVES_THE_SKADI); } void EnterEvadeMode(EvadeReason /*why*/) override @@ -234,7 +232,7 @@ public: SpawnFirstWave(); Talk(SAY_AGGRO); _phase = PHASE_FLYING; - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_LODI_DODI_WE_LOVES_THE_SKADI); + instance->TriggerGameEvent(ACHIEV_LODI_DODI_WE_LOVES_THE_SKADI); scheduler .Schedule(Seconds(6), [this](TaskContext resetCheck)