diff options
author | Shauren <shauren.trinity@gmail.com> | 2023-09-25 00:53:56 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2023-09-25 00:53:56 +0200 |
commit | 41a20b1e4008d450d075847ef1fe367f0e3a240f (patch) | |
tree | 4e202edb0d037a4a406926e6cacd686c7afcbca1 | |
parent | e1f345756ba34ccf4d4dd07b90c254097a240b51 (diff) |
Core/Achievements: Fixed achievement criteria StartEvent and FailEvent
* Criteria using StartEvent cannot be updated without that event triggering first (not only for timed achievements)
* Implemented most StartEvent and FailEvent types
* Fixed saving criteria removed by RemoveCriteriaProgress
20 files changed, 163 insertions, 239 deletions
diff --git a/sql/updates/world/master/2023_09_25_00_world.sql b/sql/updates/world/master/2023_09_25_00_world.sql new file mode 100644 index 00000000000..2f96b91d845 --- /dev/null +++ b/sql/updates/world/master/2023_09_25_00_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 e223a9ae9dd..39328c9f9c2 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -98,13 +98,6 @@ bool AchievementMgr::CanUpdateCriteriaTree(Criteria const* criteria, CriteriaTre return false; } - if (achievement->InstanceID != -1 && referencePlayer->GetMapId() != uint32(achievement->InstanceID)) - { - TC_LOG_TRACE("criteria.achievement", "AchievementMgr::CanUpdateCriteriaTree: (Id: {} Type {} Achievement {}) Wrong map", - criteria->ID, CriteriaMgr::GetCriteriaTypeString(criteria->Entry->Type), achievement->ID); - return false; - } - if ((achievement->Faction == ACHIEVEMENT_FACTION_HORDE && referencePlayer->GetTeam() != HORDE) || (achievement->Faction == ACHIEVEMENT_FACTION_ALLIANCE && referencePlayer->GetTeam() != ALLIANCE)) { @@ -369,38 +362,6 @@ void PlayerAchievementMgr::SaveToDB(CharacterDatabaseTransaction trans) } } -void PlayerAchievementMgr::ResetCriteria(CriteriaFailEvent failEvent, int32 failAsset, bool evenIfCriteriaComplete) -{ - TC_LOG_DEBUG("criteria.achievement", "PlayerAchievementMgr::ResetCriteria({}, {}, {})", uint32(failEvent), failAsset, evenIfCriteriaComplete ? "true" : "false"); - - // Disable for GameMasters with GM-mode enabled or for players that don't have the related RBAC permission - if (_owner->IsGameMaster() || _owner->GetSession()->HasPermission(rbac::RBAC_PERM_CANNOT_EARN_ACHIEVEMENTS)) - return; - - if (CriteriaList const* achievementCriteriaList = sCriteriaMgr->GetCriteriaByFailEvent(failEvent, failAsset)) - { - for (Criteria const* achievementCriteria : *achievementCriteriaList) - { - std::vector<CriteriaTree const*> const* trees = sCriteriaMgr->GetCriteriaTreesByCriteria(achievementCriteria->ID); - bool allComplete = true; - for (CriteriaTree const* tree : *trees) - { - // 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 (allComplete) - continue; - - RemoveCriteriaProgress(achievementCriteria); - } - } -} - void PlayerAchievementMgr::SendAllData(Player const* /*receiver*/) const { VisibleAchievementCheck filterInvisible; diff --git a/src/server/game/Achievements/AchievementMgr.h b/src/server/game/Achievements/AchievementMgr.h index cc17fb4c358..1d1090128a4 100644 --- a/src/server/game/Achievements/AchievementMgr.h +++ b/src/server/game/Achievements/AchievementMgr.h @@ -85,8 +85,6 @@ public: void LoadFromDB(PreparedQueryResult achievementResult, PreparedQueryResult criteriaResult); void SaveToDB(CharacterDatabaseTransaction trans); - void ResetCriteria(CriteriaFailEvent failEvent, int32 failAsset, bool evenIfCriteriaComplete = false); - void SendAllData(Player const* receiver) const override; void SendAchievementInfo(Player* receiver, uint32 achievementId = 0) const; diff --git a/src/server/game/Achievements/CriteriaHandler.cpp b/src/server/game/Achievements/CriteriaHandler.cpp index 2f10bc605fd..9abf7721db4 100644 --- a/src/server/game/Achievements/CriteriaHandler.cpp +++ b/src/server/game/Achievements/CriteriaHandler.cpp @@ -859,75 +859,94 @@ void CriteriaHandler::UpdateCriteria(CriteriaType type, uint64 miscValue1 /*= 0* } } -void CriteriaHandler::UpdateTimedCriteria(uint32 timeDiff) +void CriteriaHandler::UpdateTimedCriteria(Milliseconds timeDiff) { - if (!_timeCriteriaTrees.empty()) + for (auto itr = _startedCriteria.begin(); itr != _startedCriteria.end();) { - for (auto itr = _timeCriteriaTrees.begin(); itr != _timeCriteriaTrees.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) - { - CriteriaTree const* criteriaTree = sCriteriaMgr->GetCriteriaTree(itr->first); - if (criteriaTree->Criteria) - RemoveCriteriaProgress(criteriaTree->Criteria); + RemoveCriteriaProgress(sCriteriaMgr->GetCriteria(itr->first)); - itr = _timeCriteriaTrees.erase(itr); - } - else - { - itr->second -= timeDiff; - ++itr; - } + itr = _startedCriteria.erase(itr); + } + else + { + itr->second -= timeDiff; + ++itr; } } } -void CriteriaHandler::StartCriteriaTimer(CriteriaStartEvent startEvent, uint32 entry, uint32 timeLost /* = 0 */) +void CriteriaHandler::StartCriteria(CriteriaStartEvent startEvent, uint32 entry, Milliseconds timeLost /*= Milliseconds::zero()*/) { - CriteriaList const& criteriaList = sCriteriaMgr->GetTimedCriteriaByType(startEvent); - for (Criteria const* criteria : criteriaList) + CriteriaList const* criteriaList = sCriteriaMgr->GetCriteriaByStartEvent(startEvent, entry); + if (!criteriaList) + return; + + for (Criteria const* criteria : *criteriaList) { - if (criteria->Entry->StartAsset != int32(entry)) + Milliseconds timeLimit = Milliseconds::max(); // this value is for criteria that have a start event requirement but no time limit + if (criteria->Entry->StartTimer) + timeLimit = Seconds(criteria->Entry->StartTimer); + + timeLimit -= timeLost; + + if (timeLimit <= Milliseconds::zero()) continue; CriteriaTreeList const* trees = sCriteriaMgr->GetCriteriaTreesByCriteria(criteria->ID); - bool canStart = false; - for (CriteriaTree const* tree : *trees) + bool canStart = std::any_of(trees->begin(), trees->end(), [&](CriteriaTree const* tree) { - if ((_timeCriteriaTrees.find(tree->ID) == _timeCriteriaTrees.end() || criteria->Entry->GetFlags().HasFlag(CriteriaFlags::ResetOnStart)) && !IsCompletedCriteriaTree(tree)) - { - // Start the timer - if (criteria->Entry->StartTimer * uint32(IN_MILLISECONDS) > timeLost) - { - _timeCriteriaTrees[tree->ID] = criteria->Entry->StartTimer * IN_MILLISECONDS - timeLost; - canStart = true; - } - } - } + return !IsCompletedCriteriaTree(tree); + }); if (!canStart) continue; + auto [itr, isNew] = _startedCriteria.try_emplace(criteria->ID, timeLimit); + if (!isNew) + { + if (!criteria->Entry->GetFlags().HasFlag(CriteriaFlags::ResetOnStart)) + continue; + + itr->second = timeLimit; + } + // and at client too SetCriteriaProgress(criteria, 0, nullptr, PROGRESS_SET); } } -void CriteriaHandler::RemoveCriteriaTimer(CriteriaStartEvent startEvent, uint32 entry) +void CriteriaHandler::FailCriteria(CriteriaFailEvent failEvent, uint32 asset) { - CriteriaList const& criteriaList = sCriteriaMgr->GetTimedCriteriaByType(startEvent); - for (Criteria const* criteria : criteriaList) + CriteriaList const* criteriaList = sCriteriaMgr->GetCriteriaByFailEvent(failEvent, asset); + if (!criteriaList) + return; + + for (Criteria const* criteria : *criteriaList) { - if (criteria->Entry->StartAsset != int32(entry)) - continue; + _startedCriteria.erase(criteria->ID); CriteriaTreeList const* trees = sCriteriaMgr->GetCriteriaTreesByCriteria(criteria->ID); - // Remove the timer from all trees - for (CriteriaTree const* tree : *trees) - _timeCriteriaTrees.erase(tree->ID); + bool allTreesFullyComplete = std::all_of(trees->begin(), trees->end(), [&](CriteriaTree const* tree) + { + CriteriaTree const* root = tree; + if (CriteriaTree const* parent = sCriteriaMgr->GetCriteriaTree(root->Entry->Parent)) + { + do + { + root = parent; + parent = sCriteriaMgr->GetCriteriaTree(root->Entry->Parent); + } while (parent); + } + + return IsCompletedCriteriaTree(root); + }); + + if (allTreesFullyComplete) + continue; - // remove progress RemoveCriteriaProgress(criteria); } } @@ -943,29 +962,6 @@ CriteriaProgress* CriteriaHandler::GetCriteriaProgress(Criteria const* entry) 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({}, {}) for {}", criteria->ID, changeValue, GetOwnerInfo()); CriteriaProgress* progress = GetCriteriaProgress(criteria); @@ -1014,20 +1010,22 @@ void CriteriaHandler::SetCriteriaProgress(Criteria const* criteria, uint64 chang if (criteria->Entry->StartTimer) { - ASSERT(trees); - - for (CriteriaTree const* tree : *trees) + auto startedItr = _startedCriteria.find(criteria->ID); + if (startedItr != _startedCriteria.end()) { - auto timedIter = _timeCriteriaTrees.find(tree->ID); - if (timedIter != _timeCriteriaTrees.end()) + // Client expects this in packet + timeElapsed = duration_cast<Seconds>(Seconds(criteria->Entry->StartTimer) - startedItr->second); + + // Remove the timer, we wont need it anymore + CriteriaTreeList const* trees = sCriteriaMgr->GetCriteriaTreesByCriteria(criteria->ID); + + bool allTreesCompleted = std::all_of(trees->begin(), trees->end(), [&](CriteriaTree const* tree) { - // Client expects this in packet - timeElapsed = Seconds(criteria->Entry->StartTimer - (timedIter->second / IN_MILLISECONDS)); + return IsCompletedCriteriaTree(tree); + }); - // Remove the timer, we wont need it anymore - if (IsCompletedCriteriaTree(tree)) - _timeCriteriaTrees.erase(timedIter); - } + if (allTreesCompleted) + _startedCriteria.erase(startedItr); } } @@ -1045,7 +1043,8 @@ void CriteriaHandler::RemoveCriteriaProgress(Criteria const* criteria) SendCriteriaProgressRemoved(criteria->ID); - _criteriaProgress.erase(criteriaProgress); + criteriaProgress->second.Counter = 0; + criteriaProgress->second.Changed = true; } bool CriteriaHandler::IsCompletedCriteriaTree(CriteriaTree const* tree) @@ -1322,24 +1321,10 @@ bool CriteriaHandler::CanUpdateCriteria(Criteria const* criteria, CriteriaTreeLi return true; } -bool CriteriaHandler::ConditionsSatisfied(Criteria const* criteria, Player* referencePlayer) const +bool CriteriaHandler::ConditionsSatisfied(Criteria const* criteria, Player* /*referencePlayer*/) const { - if (!criteria->Entry->FailEvent) - return true; - - switch (CriteriaFailEvent(criteria->Entry->FailEvent)) - { - case CriteriaFailEvent::LeaveBattleground: - if (!referencePlayer->InBattleground()) - return false; - break; - case CriteriaFailEvent::ModifyPartyStatus: - if (referencePlayer->GetGroup()) - return false; - break; - default: - break; - } + if (criteria->Entry->StartEvent && !_startedCriteria.contains(criteria->ID)) + return false; return true; } @@ -4496,6 +4481,16 @@ CriteriaList const& CriteriaMgr::GetScenarioCriteriaByTypeAndScenario(CriteriaTy return EmptyCriteriaList; } +CriteriaList const* CriteriaMgr::GetCriteriaByStartEvent(CriteriaStartEvent startEvent, int32 asset) const +{ + return Trinity::Containers::MapGetValuePtr(_criteriasByStartEvent[size_t(startEvent)], asset); +} + +CriteriaList const* CriteriaMgr::GetCriteriaByFailEvent(CriteriaFailEvent failEvent, int32 asset) const +{ + return Trinity::Containers::MapGetValuePtr(_criteriasByFailEvent[size_t(failEvent)], asset); +} + CriteriaMgr::CriteriaMgr() = default; //========================================================== @@ -4720,7 +4715,7 @@ void CriteriaMgr::LoadCriteriaList() } if (criteriaEntry->StartTimer) - _criteriasByTimedType[criteriaEntry->StartEvent].push_back(criteria); + _criteriasByStartEvent[criteriaEntry->StartEvent][criteriaEntry->StartAsset].push_back(criteria); if (criteriaEntry->FailEvent) _criteriasByFailEvent[criteriaEntry->FailEvent][criteriaEntry->FailAsset].push_back(criteria); diff --git a/src/server/game/Achievements/CriteriaHandler.h b/src/server/game/Achievements/CriteriaHandler.h index 351f97bdf6f..0205130cdc0 100644 --- a/src/server/game/Achievements/CriteriaHandler.h +++ b/src/server/game/Achievements/CriteriaHandler.h @@ -22,7 +22,6 @@ #include "DBCEnums.h" #include "Duration.h" #include "ObjectGuid.h" -#include <map> #include <unordered_map> #include <vector> #include <ctime> @@ -69,8 +68,8 @@ struct CriteriaTree CriteriaTreeEntry const* Entry = nullptr; AchievementEntry const* Achievement = nullptr; ScenarioStepEntry const* ScenarioStep = nullptr; - struct QuestObjective const* QuestObjective = nullptr; - struct Criteria const* Criteria = nullptr; + ::QuestObjective const* QuestObjective = nullptr; + ::Criteria const* Criteria = nullptr; std::vector<CriteriaTree const*> Children; }; @@ -252,7 +251,6 @@ private: std::vector<CriteriaData> _storage; }; -typedef std::map<uint32, CriteriaDataSet> CriteriaDataMap; typedef std::unordered_map<uint32, CriteriaProgress> CriteriaProgressMap; enum ProgressType @@ -279,9 +277,9 @@ public: virtual void SendAllData(Player const* receiver) const = 0; - void UpdateTimedCriteria(uint32 timeDiff); - void StartCriteriaTimer(CriteriaStartEvent startEvent, uint32 entry, uint32 timeLost = 0); - void RemoveCriteriaTimer(CriteriaStartEvent startEvent, uint32 entry); // used for quest and scripted timed s + void UpdateTimedCriteria(Milliseconds timeDiff); + void StartCriteria(CriteriaStartEvent startEvent, uint32 entry, Milliseconds timeLost = Milliseconds::zero()); + virtual void FailCriteria(CriteriaFailEvent failEvent, uint32 asset); protected: virtual void SendCriteriaUpdate(Criteria const* criteria, CriteriaProgress const* progress, Seconds timeElapsed, bool timedCompleted) const = 0; @@ -312,7 +310,7 @@ protected: virtual CriteriaList const& GetCriteriaByType(CriteriaType type, uint32 asset) const = 0; CriteriaProgressMap _criteriaProgress; - std::map<uint32, uint32 /*ms time left*/> _timeCriteriaTrees; + std::unordered_map<uint32 /*criteriaID*/, Milliseconds /*time left*/> _startedCriteria; }; class TC_GAME_API CriteriaMgr @@ -351,20 +349,13 @@ public: return itr != _criteriaTreeByCriteria.end() ? &itr->second : nullptr; } - CriteriaList const& GetTimedCriteriaByType(CriteriaStartEvent startEvent) const - { - return _criteriasByTimedType[size_t(startEvent)]; - } + CriteriaList const* GetCriteriaByStartEvent(CriteriaStartEvent startEvent, int32 asset) const; - CriteriaList const* GetCriteriaByFailEvent(CriteriaFailEvent condition, int32 asset) - { - auto itr = _criteriasByFailEvent[size_t(condition)].find(asset); - return itr != _criteriasByFailEvent[size_t(condition)].end() ? &itr->second : nullptr; - } + CriteriaList const* GetCriteriaByFailEvent(CriteriaFailEvent failEvent, int32 asset) const; CriteriaDataSet const* GetCriteriaDataSet(Criteria const* Criteria) const { - CriteriaDataMap::const_iterator iter = _criteriaDataMap.find(Criteria->ID); + auto iter = _criteriaDataMap.find(Criteria->ID); return iter != _criteriaDataMap.end() ? &iter->second : nullptr; } @@ -403,7 +394,7 @@ public: ModifierTreeNode const* GetModifierTree(uint32 modifierTreeId) const; private: - CriteriaDataMap _criteriaDataMap; + std::unordered_map<uint32, CriteriaDataSet> _criteriaDataMap; std::unordered_map<uint32, CriteriaTree*> _criteriaTrees; std::unordered_map<uint32, Criteria*> _criteria; @@ -419,7 +410,7 @@ private: CriteriaListByAsset _scenarioCriteriasByTypeAndScenarioId[size_t(CriteriaType::Count)]; CriteriaList _questObjectiveCriteriasByType[size_t(CriteriaType::Count)]; - CriteriaList _criteriasByTimedType[size_t(CriteriaStartEvent::Count)]; + std::unordered_map<int32, CriteriaList> _criteriasByStartEvent[size_t(CriteriaStartEvent::Count)]; std::unordered_map<int32, CriteriaList> _criteriasByFailEvent[size_t(CriteriaFailEvent::Count)]; }; diff --git a/src/server/game/Battlegrounds/Arena.cpp b/src/server/game/Battlegrounds/Arena.cpp index d90a18bc153..c5060c40ce6 100644 --- a/src/server/game/Battlegrounds/Arena.cpp +++ b/src/server/game/Battlegrounds/Arena.cpp @@ -244,6 +244,7 @@ void Arena::EndBattleground(uint32 winner) { // update achievement BEFORE personal rating update uint32 rating = player->GetArenaPersonalRating(winnerArenaTeam->GetSlot()); + player->StartCriteria(CriteriaStartEvent::WinRankedArenaMatchWithTeamSize, 0); player->UpdateCriteria(CriteriaType::WinAnyRankedArena, rating ? rating : 1); player->UpdateCriteria(CriteriaType::WinArena, GetMapId()); @@ -269,7 +270,7 @@ void Arena::EndBattleground(uint32 winner) loserArenaTeam->MemberLost(player, winnerMatchmakerRating, loserMatchmakerChange); // Arena lost => reset the win_rated_arena having the "no_lose" condition - player->ResetCriteria(CriteriaFailEvent::LoseRankedArenaMatchWithTeamSize, 0); + player->FailCriteria(CriteriaFailEvent::LoseRankedArenaMatchWithTeamSize, 0); } } diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index 35c037159f9..56788c7d520 100644 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -418,8 +418,13 @@ inline void Battleground::_ProcessJoin(uint32 diff) SendPacketToAll(WorldPackets::Battleground::PVPMatchSetState(WorldPackets::Battleground::PVPMatchState::Engaged).Write()); for (auto const& [guid, _] : GetPlayers()) - if (Player* player = ObjectAccessor::FindPlayer(guid)) + { + if (Player* player = ObjectAccessor::GetPlayer(GetBgMap(), guid)) + { + player->StartCriteria(CriteriaStartEvent::StartBattleground, GetBgMap()->GetId()); player->AtStartOfEncounter(EncounterType::Battleground); + } + } // Remove preparation if (isArena()) @@ -929,7 +934,7 @@ void Battleground::RemovePlayerAtLeave(ObjectGuid guid, bool Transport, bool Sen player->SetBGTeam(0); // remove all criterias on bg leave - player->ResetCriteria(CriteriaFailEvent::LeaveBattleground, GetMapId(), true); + player->FailCriteria(CriteriaFailEvent::LeaveBattleground, 0); if (Transport) player->TeleportToBGEntryPoint(); @@ -1096,10 +1101,6 @@ void Battleground::AddPlayer(Player* player, BattlegroundQueueTypeId queueId) } } - // reset all map criterias on map enter - if (!isInBattleground) - player->ResetCriteria(CriteriaFailEvent::LeaveBattleground, GetMapId(), true); - // setup BG group membership PlayerAddedToBGCheckIfBGIsRunning(player); AddOrSetPlayerToCorrectBgGroup(player, team); diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp index 6a64373e8ef..b41fb4a8966 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp @@ -472,7 +472,7 @@ void BattlegroundWS::OnFlagStateChange(GameObject* flagInBase, FlagState /*oldVa ApplyAssaultDebuffToPlayer(player); flagInBase->CastSpell(player, BG_WS_SPELL_QUICK_CAP_TIMER, true); - player->StartCriteriaTimer(CriteriaStartEvent::BeSpellTarget, BG_WS_SPELL_QUICK_CAP_TIMER, uint32(GameTime::GetGameTime() - flagInBase->GetFlagTakenFromBaseTime())); + player->StartCriteria(CriteriaStartEvent::BeSpellTarget, BG_WS_SPELL_QUICK_CAP_TIMER, Seconds(GameTime::GetGameTime() - flagInBase->GetFlagTakenFromBaseTime())); break; } case FlagState::Respawning: diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 54d37c7bbb7..10f11f08bf5 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -1004,7 +1004,7 @@ void Player::Update(uint32 p_time) } } - m_achievementMgr->UpdateTimedCriteria(p_time); + m_achievementMgr->UpdateTimedCriteria(Milliseconds(p_time)); if (HasUnitState(UNIT_STATE_MELEE_ATTACKING) && !HasUnitState(UNIT_STATE_CASTING | UNIT_STATE_CHARGING)) { @@ -1262,7 +1262,7 @@ void Player::setDeathState(DeathState s) UpdateCriteria(CriteriaType::DieInInstance, 1); // reset all death criterias - ResetCriteria(CriteriaFailEvent::Death, 0); + FailCriteria(CriteriaFailEvent::Death, 0); } Unit::setDeathState(s); @@ -2408,6 +2408,7 @@ void Player::GiveLevel(uint8 level) CharacterDatabase.CommitTransaction(trans); } + StartCriteria(CriteriaStartEvent::ReachLevel, level); UpdateCriteria(CriteriaType::ReachLevel); UpdateCriteria(CriteriaType::ActivelyReachLevel, level); @@ -14975,7 +14976,7 @@ void Player::AddQuest(Quest const* quest, Object* questGiver) m_QuestStatusSave[quest_id] = QUEST_DEFAULT_SAVE_TYPE; - StartCriteriaTimer(CriteriaStartEvent::AcceptQuest, quest_id); + StartCriteria(CriteriaStartEvent::AcceptQuest, quest_id); SendQuestUpdate(quest_id); @@ -15306,6 +15307,7 @@ void Player::RewardQuest(Quest const* quest, LootItemType rewardType, uint32 rew SetDailyQuestStatus(quest_id); if (quest->IsDaily()) { + StartCriteria(CriteriaStartEvent::CompleteDailyQuest, 0); UpdateCriteria(CriteriaType::CompleteDailyQuest, quest_id); UpdateCriteria(CriteriaType::CompleteAnyDailyQuestPerDay, quest_id); } @@ -16546,7 +16548,7 @@ void Player::KilledMonsterCredit(uint32 entry, ObjectGuid guid /*= ObjectGuid::E real_entry = killed->GetEntry(); } - StartCriteriaTimer(CriteriaStartEvent::KillNPC, real_entry); // MUST BE CALLED FIRST + StartCriteria(CriteriaStartEvent::KillNPC, real_entry); // MUST BE CALLED FIRST UpdateCriteria(CriteriaType::KillCreature, real_entry, addKillCount, 0, killed); UpdateQuestObjectiveProgress(QUEST_OBJECTIVE_MONSTER, entry, 1, guid); @@ -16554,6 +16556,7 @@ void Player::KilledMonsterCredit(uint32 entry, ObjectGuid guid /*= ObjectGuid::E void Player::KilledPlayerCredit(ObjectGuid victimGuid) { + StartCriteria(CriteriaStartEvent::KillPlayer, 0); UpdateQuestObjectiveProgress(QUEST_OBJECTIVE_PLAYERKILLS, 0, 1, victimGuid); } @@ -24582,6 +24585,8 @@ void Player::DailyReset() if (_garrison) _garrison->ResetFollowerActivationLimit(); + + FailCriteria(CriteriaFailEvent::DailyQuestsCleared, 0); } void Player::ResetWeeklyQuestStatus() @@ -26402,20 +26407,15 @@ bool Player::HasAchieved(uint32 achievementId) const return m_achievementMgr->HasAchieved(achievementId); } -void Player::StartCriteriaTimer(CriteriaStartEvent startEvent, uint32 entry, uint32 timeLost/* = 0*/) -{ - m_achievementMgr->StartCriteriaTimer(startEvent, entry, timeLost); -} - -void Player::RemoveCriteriaTimer(CriteriaStartEvent startEvent, uint32 entry) +void Player::StartCriteria(CriteriaStartEvent startEvent, uint32 entry, Milliseconds timeLost/* = Milliseconds::zero()*/) { - m_achievementMgr->RemoveCriteriaTimer(startEvent, entry); + m_achievementMgr->StartCriteria(startEvent, entry, timeLost); } -void Player::ResetCriteria(CriteriaFailEvent condition, int32 failAsset, bool evenIfCriteriaComplete /* = false*/) +void Player::FailCriteria(CriteriaFailEvent condition, int32 failAsset) { - m_achievementMgr->ResetCriteria(condition, failAsset, evenIfCriteriaComplete); - m_questObjectiveCriteriaMgr->ResetCriteria(condition, failAsset, evenIfCriteriaComplete); + m_achievementMgr->FailCriteria(condition, failAsset); + m_questObjectiveCriteriaMgr->FailCriteria(condition, failAsset); } void Player::UpdateCriteria(CriteriaType type, uint64 miscValue1 /*= 0*/, uint64 miscValue2 /*= 0*/, uint64 miscValue3 /*= 0*/, WorldObject* ref /*= nullptr*/) diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 58adcd3424f..52cf7d7ffa7 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2638,10 +2638,9 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> std::vector<uint32> GetCompletedAchievementIds() const; bool HasAchieved(uint32 achievementId) const; void ResetAchievements(); - void ResetCriteria(CriteriaFailEvent condition, int32 failAsset, bool evenIfCriteriaComplete = false); + void FailCriteria(CriteriaFailEvent condition, int32 failAsset); void UpdateCriteria(CriteriaType type, uint64 miscValue1 = 0, uint64 miscValue2 = 0, uint64 miscValue3 = 0, WorldObject* ref = nullptr); - void StartCriteriaTimer(CriteriaStartEvent startEvent, uint32 entry, uint32 timeLost = 0); - void RemoveCriteriaTimer(CriteriaStartEvent startEvent, uint32 entry); + void StartCriteria(CriteriaStartEvent startEvent, uint32 entry, Milliseconds timeLost = Milliseconds::zero()); void CompletedAchievement(AchievementEntry const* entry); bool ModifierTreeSatisfied(uint32 modifierTreeId) const; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index c017eb0261c..7f4b58621b5 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -3351,8 +3351,14 @@ void Unit::_ApplyAura(AuraApplication* aurApp, uint32 effMask) } if (Player* player = ToPlayer()) + { if (sConditionMgr->IsSpellUsedInSpellClickConditions(aurApp->GetBase()->GetId())) player->UpdateVisibleGameobjectsOrSpellClicks(); + + player->FailCriteria(CriteriaFailEvent::GainAura, aurApp->GetBase()->GetId()); + player->StartCriteria(CriteriaStartEvent::GainAura, aurApp->GetBase()->GetId()); + player->UpdateCriteria(CriteriaType::GainAura, aurApp->GetBase()->GetId()); + } } // removes aura application from lists and unapplies effects @@ -3440,9 +3446,13 @@ void Unit::_UnapplyAura(AuraApplicationMap::iterator& i, AuraRemoveMode removeMo aura->HandleAuraSpecificMods(aurApp, caster, false, false); if (Player* player = ToPlayer()) + { if (sConditionMgr->IsSpellUsedInSpellClickConditions(aurApp->GetBase()->GetId())) player->UpdateVisibleGameobjectsOrSpellClicks(); + player->FailCriteria(CriteriaFailEvent::LoseAura, aurApp->GetBase()->GetId()); + } + i = m_appliedAuras.begin(); } @@ -3503,7 +3513,14 @@ void Unit::_RemoveNoStackAurasDueToAura(Aura* aura) void Unit::_RegisterAuraEffect(AuraEffect* aurEff, bool apply) { if (apply) + { m_modAuras[aurEff->GetAuraType()].push_front(aurEff); + if (Player* player = ToPlayer()) + { + player->StartCriteria(CriteriaStartEvent::GainAuraEffect, aurEff->GetAuraType()); + player->FailCriteria(CriteriaFailEvent::GainAuraEffect, aurEff->GetAuraType()); + } + } else Trinity::Containers::Lists::RemoveUnique(m_modAuras[aurEff->GetAuraType()], aurEff); } diff --git a/src/server/game/Events/GameEventSender.cpp b/src/server/game/Events/GameEventSender.cpp index da1dd86601e..031f806557a 100644 --- a/src/server/game/Events/GameEventSender.cpp +++ b/src/server/game/Events/GameEventSender.cpp @@ -56,8 +56,8 @@ void GameEvents::TriggerForPlayer(uint32 gameEventId, Player* source) Map* map = source->GetMap(); if (map->Instanceable()) { - source->StartCriteriaTimer(CriteriaStartEvent::SendEvent, gameEventId); - source->ResetCriteria(CriteriaFailEvent::SendEvent, gameEventId); + source->FailCriteria(CriteriaFailEvent::SendEvent, gameEventId); + source->StartCriteria(CriteriaStartEvent::SendEvent, gameEventId); } source->UpdateCriteria(CriteriaType::PlayerTriggerGameEvent, gameEventId, 0, 0, source); diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index ee431dca54f..38180e3abd6 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -505,6 +505,8 @@ bool Group::AddMember(Player* player) if (isRaidGroup()) player->UpdateVisibleGameobjectsOrSpellClicks(); + player->FailCriteria(CriteriaFailEvent::ModifyPartyStatus, 0); + { // Broadcast new player group member fields to rest of the group UpdateData groupData(player->GetMapId()); @@ -571,6 +573,9 @@ bool Group::RemoveMember(ObjectGuid guid, RemoveMethod method /*= GROUP_REMOVEME if (isLFGGroup() && method == GROUP_REMOVEMETHOD_KICK) return !m_memberSlots.empty(); + if (player) + player->FailCriteria(CriteriaFailEvent::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 03350379b7f..889a98d8011 100644 --- a/src/server/game/Handlers/QuestHandler.cpp +++ b/src/server/game/Handlers/QuestHandler.cpp @@ -471,7 +471,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->RemoveCriteriaTimer(CriteriaStartEvent::AcceptQuest, questId); TC_LOG_INFO("network", "Player {} abandoned quest {}", _player->GetGUID().ToString(), questId); diff --git a/src/server/game/Quests/QuestObjectiveCriteriaMgr.cpp b/src/server/game/Quests/QuestObjectiveCriteriaMgr.cpp index fe0efd9e1ef..a72c213a042 100644 --- a/src/server/game/Quests/QuestObjectiveCriteriaMgr.cpp +++ b/src/server/game/Quests/QuestObjectiveCriteriaMgr.cpp @@ -164,38 +164,6 @@ void QuestObjectiveCriteriaMgr::SaveToDB(CharacterDatabaseTransaction trans) } } -void QuestObjectiveCriteriaMgr::ResetCriteria(CriteriaFailEvent failEvent, int32 failAsset, bool evenIfCriteriaComplete) -{ - TC_LOG_DEBUG("criteria.quest", "QuestObjectiveCriteriaMgr::ResetCriteria({}, {}, {})", uint32(failEvent), failAsset, evenIfCriteriaComplete ? "true" : "false"); - - // disable for gamemasters with GM-mode enabled - if (_owner->IsGameMaster()) - return; - - if (CriteriaList const* playerCriteriaList = sCriteriaMgr->GetCriteriaByFailEvent(failEvent, failAsset)) - { - for (Criteria const* playerCriteria : *playerCriteriaList) - { - std::vector<CriteriaTree const*> const* trees = sCriteriaMgr->GetCriteriaTreesByCriteria(playerCriteria->ID); - bool allComplete = true; - for (CriteriaTree const* tree : *trees) - { - // don't update already completed criteria if not forced - if (!(IsCompletedCriteriaTree(tree) && !evenIfCriteriaComplete)) - { - allComplete = false; - break; - } - } - - if (allComplete) - continue; - - RemoveCriteriaProgress(playerCriteria); - } - } -} - void QuestObjectiveCriteriaMgr::ResetCriteriaTree(uint32 criteriaTreeId) { CriteriaTree const* tree = sCriteriaMgr->GetCriteriaTree(criteriaTreeId); diff --git a/src/server/game/Quests/QuestObjectiveCriteriaMgr.h b/src/server/game/Quests/QuestObjectiveCriteriaMgr.h index ca1eac58a15..a263e153316 100644 --- a/src/server/game/Quests/QuestObjectiveCriteriaMgr.h +++ b/src/server/game/Quests/QuestObjectiveCriteriaMgr.h @@ -35,7 +35,6 @@ public: void LoadFromDB(PreparedQueryResult objectiveResult, PreparedQueryResult criteriaResult); void SaveToDB(CharacterDatabaseTransaction trans); - void ResetCriteria(CriteriaFailEvent failEvent, int32 failAsset, bool evenIfCriteriaComplete = false); void ResetCriteriaTree(uint32 criteriaTreeId); void SendAllData(Player const* receiver) const override; diff --git a/src/server/game/Scenarios/Scenario.cpp b/src/server/game/Scenarios/Scenario.cpp index 6d8fd3c1c62..3366781ba39 100644 --- a/src/server/game/Scenarios/Scenario.cpp +++ b/src/server/game/Scenarios/Scenario.cpp @@ -93,7 +93,12 @@ void Scenario::SetStep(ScenarioStepEntry const* step) { _currentstep = step; if (step) + { SetStepState(step, SCENARIO_STEP_IN_PROGRESS); + for (ObjectGuid const& guid : _players) + if (Player* player = ObjectAccessor::GetPlayer(_map, guid)) + player->StartCriteria(CriteriaStartEvent::BeginScenarioStep, step->ID); + } WorldPackets::Scenario::ScenarioState scenarioState; BuildScenarioState(&scenarioState); @@ -133,7 +138,7 @@ ScenarioEntry const* Scenario::GetEntry() const ScenarioStepState Scenario::GetStepState(ScenarioStepEntry const* step) { - std::map<ScenarioStepEntry const*, ScenarioStepState>::const_iterator itr = _stepStates.find(step); + auto itr = _stepStates.find(step); if (itr == _stepStates.end()) return SCENARIO_STEP_INVALID; diff --git a/src/server/game/Scenarios/Scenario.h b/src/server/game/Scenarios/Scenario.h index e01884dd9a9..7c632eca0cb 100644 --- a/src/server/game/Scenarios/Scenario.h +++ b/src/server/game/Scenarios/Scenario.h @@ -19,6 +19,7 @@ #define Scenario_h__ #include "CriteriaHandler.h" +#include <map> #include <unordered_set> class Map; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 19a68fa341d..4ba4c975c6e 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -3087,16 +3087,13 @@ SpellMissInfo Spell::PreprocessSpellHit(Unit* unit, TargetInfo& hitInfo) if (Player* player = unit->ToPlayer()) { - player->StartCriteriaTimer(CriteriaStartEvent::BeSpellTarget, m_spellInfo->Id); + player->FailCriteria(CriteriaFailEvent::BeSpellTarget, m_spellInfo->Id); + player->StartCriteria(CriteriaStartEvent::BeSpellTarget, m_spellInfo->Id); player->UpdateCriteria(CriteriaType::BeSpellTarget, m_spellInfo->Id, 0, 0, m_caster); - player->UpdateCriteria(CriteriaType::GainAura, m_spellInfo->Id); } if (Player* player = m_caster->ToPlayer()) - { - player->StartCriteriaTimer(CriteriaStartEvent::CastSpell, m_spellInfo->Id); player->UpdateCriteria(CriteriaType::LandTargetedSpellOnTarget, m_spellInfo->Id, 0, 0, unit); - } if (m_caster != unit) { @@ -3791,10 +3788,12 @@ void Spell::_cast(bool skipCheck) { if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CAST_ITEM) && m_CastItem) { - player->StartCriteriaTimer(CriteriaStartEvent::UseItem, m_CastItem->GetEntry()); + player->StartCriteria(CriteriaStartEvent::UseItem, m_CastItem->GetEntry()); player->UpdateCriteria(CriteriaType::UseItem, m_CastItem->GetEntry()); } + player->FailCriteria(CriteriaFailEvent::CastSpell, m_spellInfo->Id); + player->StartCriteria(CriteriaStartEvent::CastSpell, m_spellInfo->Id); player->UpdateCriteria(CriteriaType::CastSpell, m_spellInfo->Id); } 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 84262234a81..f823561a2ea 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 @@ -1183,21 +1183,6 @@ class spell_algalon_cosmic_smash_damage : public SpellScript } }; -// 65311 - Supermassive Fail -class spell_algalon_supermassive_fail : public SpellScript -{ - void RecalculateDamage() - { - if (Player* player = GetHitPlayer()) - player->ResetCriteria(CriteriaFailEvent::BeSpellTarget, GetSpellInfo()->Id, true); - } - - void Register() override - { - OnHit += SpellHitFn(spell_algalon_supermassive_fail::RecalculateDamage); - } -}; - // 62168 - Black Hole (Phase Shifts) // 65250 - Worm Hole (Phase Shifts) // 64417 - Phase Punch (Phase Shifts) @@ -1240,6 +1225,5 @@ void AddSC_boss_algalon_the_observer() RegisterSpellScript(spell_algalon_remove_phase); RegisterSpellScript(spell_algalon_cosmic_smash); RegisterSpellScript(spell_algalon_cosmic_smash_damage); - RegisterSpellScript(spell_algalon_supermassive_fail); RegisterSpellScript(spell_algalon_black_hole_phase_shifts); } |