diff options
author | Shauren <shauren.trinity@gmail.com> | 2024-12-08 00:23:38 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2024-12-08 00:23:38 +0100 |
commit | 4e89a302fcce7644bcd8cf239edad3b409950438 (patch) | |
tree | 3bffaa439377f092840d757d74f09c40004f4411 | |
parent | 6da1679cbfdc56cd5f1cab7148f645916bccecc1 (diff) |
Core/Quests: Improved criteria tree quest objective type
* Fixed _completedObjectives not being cleaned when adding quest
* Fixed objective credit being granted if just the criteria tree row containing criteria id was completed (instead of the entire tree linked to objective)
* Retroactively grant progress on quest accept for criteria types that require action that cannot be repeated (such as learning a spell)
-rw-r--r-- | src/server/game/Achievements/CriteriaHandler.cpp | 701 | ||||
-rw-r--r-- | src/server/game/Achievements/CriteriaHandler.h | 2 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Quests/QuestObjectiveCriteriaMgr.cpp | 18 | ||||
-rw-r--r-- | src/server/game/Quests/QuestObjectiveCriteriaMgr.h | 2 |
5 files changed, 370 insertions, 355 deletions
diff --git a/src/server/game/Achievements/CriteriaHandler.cpp b/src/server/game/Achievements/CriteriaHandler.cpp index 783eb38daad..d7df88bb8e1 100644 --- a/src/server/game/Achievements/CriteriaHandler.cpp +++ b/src/server/game/Achievements/CriteriaHandler.cpp @@ -489,382 +489,385 @@ void CriteriaHandler::UpdateCriteria(CriteriaType type, uint64 miscValue1 /*= 0* CriteriaList const& criteriaList = GetCriteriaByType(type, uint32(miscValue1)); for (Criteria const* criteria : criteriaList) + UpdateCriteria(criteria, miscValue1, miscValue2, miscValue3, ref, referencePlayer); +} + +void CriteriaHandler::UpdateCriteria(Criteria const* criteria, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, WorldObject const* ref, Player* referencePlayer) +{ + CriteriaTreeList const* trees = sCriteriaMgr->GetCriteriaTreesByCriteria(criteria->ID); + if (!CanUpdateCriteria(criteria, trees, miscValue1, miscValue2, miscValue3, ref, referencePlayer)) + return; + + // requirements not found in the dbc + if (CriteriaDataSet const* data = sCriteriaMgr->GetCriteriaDataSet(criteria)) + if (!data->Meets(referencePlayer, ref, uint32(miscValue1), uint32(miscValue2))) + return; + + switch (CriteriaType(criteria->Entry->Type)) { - CriteriaTreeList const* trees = sCriteriaMgr->GetCriteriaTreesByCriteria(criteria->ID); - if (!CanUpdateCriteria(criteria, trees, miscValue1, miscValue2, miscValue3, ref, referencePlayer)) - continue; + // std. case: increment at 1 + case CriteriaType::WinBattleground: + case CriteriaType::TotalRespecs: + case CriteriaType::LoseDuel: + case CriteriaType::ItemsPostedAtAuction: + case CriteriaType::AuctionsWon: /* FIXME: for online player only currently */ + case CriteriaType::RollAnyNeed: + case CriteriaType::RollAnyGreed: + case CriteriaType::AbandonAnyQuest: + case CriteriaType::BuyTaxi: + case CriteriaType::AcceptSummon: + case CriteriaType::LootAnyItem: + case CriteriaType::ObtainAnyItem: + case CriteriaType::DieAnywhere: + case CriteriaType::CompleteDailyQuest: + case CriteriaType::ParticipateInBattleground: + case CriteriaType::DieOnMap: + case CriteriaType::DieInInstance: + case CriteriaType::KilledByCreature: + case CriteriaType::KilledByPlayer: + case CriteriaType::DieFromEnviromentalDamage: + case CriteriaType::BeSpellTarget: + case CriteriaType::GainAura: + case CriteriaType::CastSpell: + case CriteriaType::LandTargetedSpellOnTarget: + case CriteriaType::WinAnyRankedArena: + case CriteriaType::UseItem: + case CriteriaType::RollNeed: + case CriteriaType::RollGreed: + case CriteriaType::DoEmote: + case CriteriaType::UseGameobject: + case CriteriaType::CatchFishInFishingHole: + case CriteriaType::WinDuel: + case CriteriaType::DeliverKillingBlowToClass: + case CriteriaType::DeliverKillingBlowToRace: + case CriteriaType::TrackedWorldStateUIModified: + case CriteriaType::EarnHonorableKill: + case CriteriaType::KillPlayer: + case CriteriaType::DeliveredKillingBlow: + case CriteriaType::PVPKillInArea: + case CriteriaType::WinArena: // This also behaves like CriteriaType::WinAnyRankedArena + case CriteriaType::ParticipateInArena: + case CriteriaType::PlayerTriggerGameEvent: + case CriteriaType::Login: + case CriteriaType::AnyoneTriggerGameEventScenario: + case CriteriaType::DefeatDungeonEncounterWhileElegibleForLoot: + case CriteriaType::CompleteAnyScenario: + case CriteriaType::CompleteScenario: + case CriteriaType::BattlePetReachLevel: + case CriteriaType::ActivelyEarnPetLevel: + case CriteriaType::DefeatDungeonEncounter: + case CriteriaType::PlaceGarrisonBuilding: + case CriteriaType::ActivateAnyGarrisonBuilding: + case CriteriaType::LearnAnyHeirloom: + case CriteriaType::LearnAnyTransmog: + case CriteriaType::HonorLevelIncrease: + case CriteriaType::PrestigeLevelIncrease: + case CriteriaType::LearnAnyTransmogInSlot: + case CriteriaType::CompleteAnyReplayQuest: + case CriteriaType::BuyItemsFromVendors: + case CriteriaType::SellItemsToVendors: + case CriteriaType::ReachMaxLevel: + case CriteriaType::LearnTaxiNode: + SetCriteriaProgress(criteria, 1, referencePlayer, PROGRESS_ACCUMULATE); + break; + // std case: increment at miscValue1 + case CriteriaType::MoneyEarnedFromSales: + case CriteriaType::MoneySpentOnRespecs: + case CriteriaType::MoneyEarnedFromQuesting: + case CriteriaType::MoneySpentOnTaxis: + case CriteriaType::MoneySpentAtBarberShop: + case CriteriaType::MoneySpentOnPostage: + case CriteriaType::MoneyLootedFromCreatures: + case CriteriaType::MoneyEarnedFromAuctions:/* FIXME: for online player only currently */ + case CriteriaType::TotalDamageTaken: + case CriteriaType::TotalHealReceived: + case CriteriaType::CompletedLFGDungeon: + case CriteriaType::CompletedLFGDungeonWithStrangers: + case CriteriaType::DamageDealt: + case CriteriaType::HealingDone: + case CriteriaType::EarnArtifactXPForAzeriteItem: + case CriteriaType::GainLevels: + case CriteriaType::EarnArtifactXP: + SetCriteriaProgress(criteria, miscValue1, referencePlayer, PROGRESS_ACCUMULATE); + break; + case CriteriaType::KillCreature: + case CriteriaType::KillAnyCreature: + case CriteriaType::GetLootByType: + case CriteriaType::AcquireItem: + case CriteriaType::LootItem: + case CriteriaType::CurrencyGained: + SetCriteriaProgress(criteria, miscValue2, referencePlayer, PROGRESS_ACCUMULATE); + break; + // std case: high value at miscValue1 + case CriteriaType::HighestAuctionBid: + case CriteriaType::HighestAuctionSale: /* FIXME: for online player only currently */ + case CriteriaType::HighestDamageDone: + case CriteriaType::HighestDamageTaken: + case CriteriaType::HighestHealCast: + case CriteriaType::HighestHealReceived: + case CriteriaType::AnyArtifactPowerRankPurchased: + case CriteriaType::AzeriteLevelReached: + case CriteriaType::ReachRenownLevel: + SetCriteriaProgress(criteria, miscValue1, referencePlayer, PROGRESS_HIGHEST); + break; + case CriteriaType::ReachLevel: + SetCriteriaProgress(criteria, referencePlayer->GetLevel(), referencePlayer); + break; + case CriteriaType::SkillRaised: + if (uint32 skillvalue = referencePlayer->GetBaseSkillValue(criteria->Entry->Asset.SkillID)) + SetCriteriaProgress(criteria, skillvalue, referencePlayer); + break; + case CriteriaType::AchieveSkillStep: + if (uint32 maxSkillvalue = referencePlayer->GetPureMaxSkillValue(criteria->Entry->Asset.SkillID)) + SetCriteriaProgress(criteria, maxSkillvalue, referencePlayer); + break; + case CriteriaType::CompleteQuestsCount: + SetCriteriaProgress(criteria, referencePlayer->GetRewardedQuestCount(), referencePlayer); + break; + case CriteriaType::CompleteAnyDailyQuestPerDay: + { + time_t nextDailyResetTime = sWorld->GetNextDailyQuestsResetTime(); + CriteriaProgress *progress = GetCriteriaProgress(criteria); - // requirements not found in the dbc - if (CriteriaDataSet const* data = sCriteriaMgr->GetCriteriaDataSet(criteria)) - if (!data->Meets(referencePlayer, ref, uint32(miscValue1), uint32(miscValue2))) - continue; + if (!miscValue1) // Login case. + { + // reset if player missed one day. + if (progress && progress->Date < (nextDailyResetTime - 2 * DAY)) + SetCriteriaProgress(criteria, 0, referencePlayer, PROGRESS_SET); + return; + } + + ProgressType progressType; + if (!progress) + // 1st time. Start count. + progressType = PROGRESS_SET; + else if (progress->Date < (nextDailyResetTime - 2 * DAY)) + // last progress is older than 2 days. Player missed 1 day => Restart count. + progressType = PROGRESS_SET; + else if (progress->Date < (nextDailyResetTime - DAY)) + // last progress is between 1 and 2 days. => 1st time of the day. + progressType = PROGRESS_ACCUMULATE; + else + // last progress is within the day before the reset => Already counted today. + return; - switch (type) - { - // std. case: increment at 1 - case CriteriaType::WinBattleground: - case CriteriaType::TotalRespecs: - case CriteriaType::LoseDuel: - case CriteriaType::ItemsPostedAtAuction: - case CriteriaType::AuctionsWon: /* FIXME: for online player only currently */ - case CriteriaType::RollAnyNeed: - case CriteriaType::RollAnyGreed: - case CriteriaType::AbandonAnyQuest: - case CriteriaType::BuyTaxi: - case CriteriaType::AcceptSummon: - case CriteriaType::LootAnyItem: - case CriteriaType::ObtainAnyItem: - case CriteriaType::DieAnywhere: - case CriteriaType::CompleteDailyQuest: - case CriteriaType::ParticipateInBattleground: - case CriteriaType::DieOnMap: - case CriteriaType::DieInInstance: - case CriteriaType::KilledByCreature: - case CriteriaType::KilledByPlayer: - case CriteriaType::DieFromEnviromentalDamage: - case CriteriaType::BeSpellTarget: - case CriteriaType::GainAura: - case CriteriaType::CastSpell: - case CriteriaType::LandTargetedSpellOnTarget: - case CriteriaType::WinAnyRankedArena: - case CriteriaType::UseItem: - case CriteriaType::RollNeed: - case CriteriaType::RollGreed: - case CriteriaType::DoEmote: - case CriteriaType::UseGameobject: - case CriteriaType::CatchFishInFishingHole: - case CriteriaType::WinDuel: - case CriteriaType::DeliverKillingBlowToClass: - case CriteriaType::DeliverKillingBlowToRace: - case CriteriaType::TrackedWorldStateUIModified: - case CriteriaType::EarnHonorableKill: - case CriteriaType::KillPlayer: - case CriteriaType::DeliveredKillingBlow: - case CriteriaType::PVPKillInArea: - case CriteriaType::WinArena: // This also behaves like CriteriaType::WinAnyRankedArena - case CriteriaType::ParticipateInArena: - case CriteriaType::PlayerTriggerGameEvent: - case CriteriaType::Login: - case CriteriaType::AnyoneTriggerGameEventScenario: - case CriteriaType::DefeatDungeonEncounterWhileElegibleForLoot: - case CriteriaType::CompleteAnyScenario: - case CriteriaType::CompleteScenario: - case CriteriaType::BattlePetReachLevel: - case CriteriaType::ActivelyEarnPetLevel: - case CriteriaType::DefeatDungeonEncounter: - case CriteriaType::PlaceGarrisonBuilding: - case CriteriaType::ActivateAnyGarrisonBuilding: - case CriteriaType::LearnAnyHeirloom: - case CriteriaType::LearnAnyTransmog: - case CriteriaType::HonorLevelIncrease: - case CriteriaType::PrestigeLevelIncrease: - case CriteriaType::LearnAnyTransmogInSlot: - case CriteriaType::CompleteAnyReplayQuest: - case CriteriaType::BuyItemsFromVendors: - case CriteriaType::SellItemsToVendors: - case CriteriaType::ReachMaxLevel: - case CriteriaType::LearnTaxiNode: + SetCriteriaProgress(criteria, 1, referencePlayer, progressType); + break; + } + case CriteriaType::CompleteQuestsInZone: + { + if (miscValue1) + { SetCriteriaProgress(criteria, 1, referencePlayer, PROGRESS_ACCUMULATE); - break; - // std case: increment at miscValue1 - case CriteriaType::MoneyEarnedFromSales: - case CriteriaType::MoneySpentOnRespecs: - case CriteriaType::MoneyEarnedFromQuesting: - case CriteriaType::MoneySpentOnTaxis: - case CriteriaType::MoneySpentAtBarberShop: - case CriteriaType::MoneySpentOnPostage: - case CriteriaType::MoneyLootedFromCreatures: - case CriteriaType::MoneyEarnedFromAuctions:/* FIXME: for online player only currently */ - case CriteriaType::TotalDamageTaken: - case CriteriaType::TotalHealReceived: - case CriteriaType::CompletedLFGDungeon: - case CriteriaType::CompletedLFGDungeonWithStrangers: - case CriteriaType::DamageDealt: - case CriteriaType::HealingDone: - case CriteriaType::EarnArtifactXPForAzeriteItem: - case CriteriaType::GainLevels: - case CriteriaType::EarnArtifactXP: - SetCriteriaProgress(criteria, miscValue1, referencePlayer, PROGRESS_ACCUMULATE); - break; - case CriteriaType::KillCreature: - case CriteriaType::KillAnyCreature: - case CriteriaType::GetLootByType: - case CriteriaType::AcquireItem: - case CriteriaType::LootItem: - case CriteriaType::CurrencyGained: - SetCriteriaProgress(criteria, miscValue2, referencePlayer, PROGRESS_ACCUMULATE); - break; - // std case: high value at miscValue1 - case CriteriaType::HighestAuctionBid: - case CriteriaType::HighestAuctionSale: /* FIXME: for online player only currently */ - case CriteriaType::HighestDamageDone: - case CriteriaType::HighestDamageTaken: - case CriteriaType::HighestHealCast: - case CriteriaType::HighestHealReceived: - case CriteriaType::AnyArtifactPowerRankPurchased: - case CriteriaType::AzeriteLevelReached: - case CriteriaType::ReachRenownLevel: - SetCriteriaProgress(criteria, miscValue1, referencePlayer, PROGRESS_HIGHEST); - break; - case CriteriaType::ReachLevel: - SetCriteriaProgress(criteria, referencePlayer->GetLevel(), referencePlayer); - break; - case CriteriaType::SkillRaised: - if (uint32 skillvalue = referencePlayer->GetBaseSkillValue(criteria->Entry->Asset.SkillID)) - SetCriteriaProgress(criteria, skillvalue, referencePlayer); - break; - case CriteriaType::AchieveSkillStep: - if (uint32 maxSkillvalue = referencePlayer->GetPureMaxSkillValue(criteria->Entry->Asset.SkillID)) - SetCriteriaProgress(criteria, maxSkillvalue, referencePlayer); - break; - case CriteriaType::CompleteQuestsCount: - SetCriteriaProgress(criteria, referencePlayer->GetRewardedQuestCount(), referencePlayer); - break; - case CriteriaType::CompleteAnyDailyQuestPerDay: + } + else // login case { - time_t nextDailyResetTime = sWorld->GetNextDailyQuestsResetTime(); - CriteriaProgress *progress = GetCriteriaProgress(criteria); + uint32 counter = 0; - if (!miscValue1) // Login case. + RewardedQuestSet const& rewQuests = referencePlayer->getRewardedQuests(); + for (uint32 rewQuest : rewQuests) { - // reset if player missed one day. - if (progress && progress->Date < (nextDailyResetTime - 2 * DAY)) - SetCriteriaProgress(criteria, 0, referencePlayer, PROGRESS_SET); - continue; + Quest const* quest = sObjectMgr->GetQuestTemplate(rewQuest); + if (quest && quest->GetZoneOrSort() >= 0 && quest->GetZoneOrSort() == criteria->Entry->Asset.ZoneID) + ++counter; } - - ProgressType progressType; - if (!progress) - // 1st time. Start count. - progressType = PROGRESS_SET; - else if (progress->Date < (nextDailyResetTime - 2 * DAY)) - // last progress is older than 2 days. Player missed 1 day => Restart count. - progressType = PROGRESS_SET; - else if (progress->Date < (nextDailyResetTime - DAY)) - // last progress is between 1 and 2 days. => 1st time of the day. - progressType = PROGRESS_ACCUMULATE; - else - // last progress is within the day before the reset => Already counted today. - continue; - - SetCriteriaProgress(criteria, 1, referencePlayer, progressType); - break; + SetCriteriaProgress(criteria, counter, referencePlayer, PROGRESS_HIGHEST); } - case CriteriaType::CompleteQuestsInZone: + break; + } + case CriteriaType::MaxDistFallenWithoutDying: + // miscValue1 is the ingame fallheight*100 as stored in dbc + SetCriteriaProgress(criteria, miscValue1, referencePlayer); + break; + case CriteriaType::EarnAchievement: + case CriteriaType::CompleteQuest: + case CriteriaType::LearnOrKnowSpell: + case CriteriaType::RevealWorldMapOverlay: + case CriteriaType::GotHaircut: + case CriteriaType::EquipItemInSlot: + case CriteriaType::EquipItem: + case CriteriaType::EnterAreaTriggerWithActionSet: + case CriteriaType::LeaveAreaTriggerWithActionSet: + case CriteriaType::LearnedNewPet: + case CriteriaType::EnterArea: + case CriteriaType::LeaveArea: + case CriteriaType::RecruitGarrisonFollower: + case CriteriaType::LearnHeirloom: + case CriteriaType::ActivelyReachLevel: + case CriteriaType::CollectTransmogSetFromGroup: + case CriteriaType::EnterTopLevelArea: + case CriteriaType::LeaveTopLevelArea: + SetCriteriaProgress(criteria, 1, referencePlayer); + break; + case CriteriaType::BankSlotsPurchased: + SetCriteriaProgress(criteria, referencePlayer->GetBankBagSlotCount(), referencePlayer); + break; + case CriteriaType::ReputationGained: + { + int32 reputation = referencePlayer->GetReputationMgr().GetReputation(criteria->Entry->Asset.FactionID); + if (reputation > 0) + SetCriteriaProgress(criteria, reputation, referencePlayer); + break; + } + case CriteriaType::TotalExaltedFactions: + SetCriteriaProgress(criteria, referencePlayer->GetReputationMgr().GetExaltedFactionCount(), referencePlayer); + break; + case CriteriaType::LearnSpellFromSkillLine: + case CriteriaType::LearnTradeskillSkillLine: + { + uint32 spellCount = 0; + for (auto& [spellId, _] : referencePlayer->GetSpellMap()) { - if (miscValue1) + SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellId); + for (SkillLineAbilityMap::const_iterator skillIter = bounds.first; skillIter != bounds.second; ++skillIter) { - SetCriteriaProgress(criteria, 1, referencePlayer, PROGRESS_ACCUMULATE); - } - else // login case - { - uint32 counter = 0; - - RewardedQuestSet const& rewQuests = referencePlayer->getRewardedQuests(); - for (uint32 rewQuest : rewQuests) + if (skillIter->second->SkillLine == uint32(criteria->Entry->Asset.SkillID)) { - Quest const* quest = sObjectMgr->GetQuestTemplate(rewQuest); - if (quest && quest->GetZoneOrSort() >= 0 && quest->GetZoneOrSort() == criteria->Entry->Asset.ZoneID) - ++counter; + // do not add couter twice if by any chance skill is listed twice in dbc (eg. skill 777 and spell 22717) + ++spellCount; + break; } - SetCriteriaProgress(criteria, counter, referencePlayer, PROGRESS_HIGHEST); } - break; } - case CriteriaType::MaxDistFallenWithoutDying: - // miscValue1 is the ingame fallheight*100 as stored in dbc - SetCriteriaProgress(criteria, miscValue1, referencePlayer); - break; - case CriteriaType::EarnAchievement: - case CriteriaType::CompleteQuest: - case CriteriaType::LearnOrKnowSpell: - case CriteriaType::RevealWorldMapOverlay: - case CriteriaType::GotHaircut: - case CriteriaType::EquipItemInSlot: - case CriteriaType::EquipItem: - case CriteriaType::EnterAreaTriggerWithActionSet: - case CriteriaType::LeaveAreaTriggerWithActionSet: - case CriteriaType::LearnedNewPet: - case CriteriaType::EnterArea: - case CriteriaType::LeaveArea: - case CriteriaType::RecruitGarrisonFollower: - case CriteriaType::LearnHeirloom: - case CriteriaType::ActivelyReachLevel: - case CriteriaType::CollectTransmogSetFromGroup: - case CriteriaType::EnterTopLevelArea: - case CriteriaType::LeaveTopLevelArea: - SetCriteriaProgress(criteria, 1, referencePlayer); - break; - case CriteriaType::BankSlotsPurchased: - SetCriteriaProgress(criteria, referencePlayer->GetBankBagSlotCount(), referencePlayer); - break; - case CriteriaType::ReputationGained: + SetCriteriaProgress(criteria, spellCount, referencePlayer); + break; + } + case CriteriaType::TotalReveredFactions: + SetCriteriaProgress(criteria, referencePlayer->GetReputationMgr().GetReveredFactionCount(), referencePlayer); + break; + case CriteriaType::TotalHonoredFactions: + SetCriteriaProgress(criteria, referencePlayer->GetReputationMgr().GetHonoredFactionCount(), referencePlayer); + break; + case CriteriaType::TotalFactionsEncountered: + SetCriteriaProgress(criteria, referencePlayer->GetReputationMgr().GetVisibleFactionCount(), referencePlayer); + break; + case CriteriaType::HonorableKills: + SetCriteriaProgress(criteria, referencePlayer->m_activePlayerData->LifetimeHonorableKills, referencePlayer); + break; + case CriteriaType::MostMoneyOwned: + SetCriteriaProgress(criteria, referencePlayer->GetMoney(), referencePlayer, PROGRESS_HIGHEST); + break; + case CriteriaType::EarnAchievementPoints: + if (!miscValue1) + return; + SetCriteriaProgress(criteria, miscValue1, referencePlayer, PROGRESS_ACCUMULATE); + break; + case CriteriaType::EarnPersonalArenaRating: + { + uint32 reqTeamType = criteria->Entry->Asset.TeamType; + + if (miscValue1) { - int32 reputation = referencePlayer->GetReputationMgr().GetReputation(criteria->Entry->Asset.FactionID); - if (reputation > 0) - SetCriteriaProgress(criteria, reputation, referencePlayer); - break; + if (miscValue2 != reqTeamType) + return; + + SetCriteriaProgress(criteria, miscValue1, referencePlayer, PROGRESS_HIGHEST); } - case CriteriaType::TotalExaltedFactions: - SetCriteriaProgress(criteria, referencePlayer->GetReputationMgr().GetExaltedFactionCount(), referencePlayer); - break; - case CriteriaType::LearnSpellFromSkillLine: - case CriteriaType::LearnTradeskillSkillLine: + else // login case { - uint32 spellCount = 0; - for (auto& [spellId, _] : referencePlayer->GetSpellMap()) + for (uint8 arena_slot = 0; arena_slot < MAX_ARENA_SLOT; ++arena_slot) { - SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellId); - for (SkillLineAbilityMap::const_iterator skillIter = bounds.first; skillIter != bounds.second; ++skillIter) - { - if (skillIter->second->SkillLine == uint32(criteria->Entry->Asset.SkillID)) - { - // do not add couter twice if by any chance skill is listed twice in dbc (eg. skill 777 and spell 22717) - ++spellCount; - break; - } - } - } - SetCriteriaProgress(criteria, spellCount, referencePlayer); - break; - } - case CriteriaType::TotalReveredFactions: - SetCriteriaProgress(criteria, referencePlayer->GetReputationMgr().GetReveredFactionCount(), referencePlayer); - break; - case CriteriaType::TotalHonoredFactions: - SetCriteriaProgress(criteria, referencePlayer->GetReputationMgr().GetHonoredFactionCount(), referencePlayer); - break; - case CriteriaType::TotalFactionsEncountered: - SetCriteriaProgress(criteria, referencePlayer->GetReputationMgr().GetVisibleFactionCount(), referencePlayer); - break; - case CriteriaType::HonorableKills: - SetCriteriaProgress(criteria, referencePlayer->m_activePlayerData->LifetimeHonorableKills, referencePlayer); - break; - case CriteriaType::MostMoneyOwned: - SetCriteriaProgress(criteria, referencePlayer->GetMoney(), referencePlayer, PROGRESS_HIGHEST); - break; - case CriteriaType::EarnAchievementPoints: - if (!miscValue1) - continue; - SetCriteriaProgress(criteria, miscValue1, referencePlayer, PROGRESS_ACCUMULATE); - break; - case CriteriaType::EarnPersonalArenaRating: - { - uint32 reqTeamType = criteria->Entry->Asset.TeamType; + uint32 teamId = referencePlayer->GetArenaTeamId(arena_slot); + if (!teamId) + continue; - if (miscValue1) - { - if (miscValue2 != reqTeamType) + ArenaTeam* team = sArenaTeamMgr->GetArenaTeamById(teamId); + if (!team || team->GetType() != reqTeamType) continue; - SetCriteriaProgress(criteria, miscValue1, referencePlayer, PROGRESS_HIGHEST); - } - else // login case - { - for (uint8 arena_slot = 0; arena_slot < MAX_ARENA_SLOT; ++arena_slot) + if (ArenaTeamMember const* member = team->GetMember(referencePlayer->GetGUID())) { - uint32 teamId = referencePlayer->GetArenaTeamId(arena_slot); - if (!teamId) - continue; - - ArenaTeam* team = sArenaTeamMgr->GetArenaTeamById(teamId); - if (!team || team->GetType() != reqTeamType) - continue; - - if (ArenaTeamMember const* member = team->GetMember(referencePlayer->GetGUID())) - { - SetCriteriaProgress(criteria, member->PersonalRating, referencePlayer, PROGRESS_HIGHEST); - break; - } + SetCriteriaProgress(criteria, member->PersonalRating, referencePlayer, PROGRESS_HIGHEST); + break; } } - break; } - case CriteriaType::UniquePetsOwned: - SetCriteriaProgress(criteria, referencePlayer->GetSession()->GetBattlePetMgr()->GetPetUniqueSpeciesCount(), referencePlayer); - break; - case CriteriaType::GuildAttainedLevel: - SetCriteriaProgress(criteria, miscValue1, referencePlayer); - break; - // FIXME: not triggered in code as result, need to implement - case CriteriaType::RunInstance: - case CriteriaType::EarnTeamArenaRating: - case CriteriaType::EarnTitle: - case CriteriaType::MoneySpentOnGuildRepair: - case CriteriaType::CreatedItemsByCastingSpell: - case CriteriaType::FishInAnyPool: - case CriteriaType::GuildBankTabsPurchased: - case CriteriaType::EarnGuildAchievementPoints: - case CriteriaType::WinAnyBattleground: - case CriteriaType::EarnBattlegroundRating: - case CriteriaType::GuildTabardCreated: - case CriteriaType::CompleteQuestsCountForGuild: - case CriteriaType::HonorableKillsForGuild: - case CriteriaType::KillAnyCreatureForGuild: - case CriteriaType::CompleteAnyResearchProject: - case CriteriaType::CompleteGuildChallenge: - case CriteriaType::CompleteAnyGuildChallenge: - case CriteriaType::CompletedLFRDungeon: - case CriteriaType::AbandonedLFRDungeon: - case CriteriaType::KickInitiatorInLFRDungeon: - case CriteriaType::KickVoterInLFRDungeon: - case CriteriaType::KickTargetInLFRDungeon: - case CriteriaType::GroupedTankLeftEarlyInLFRDungeon: - case CriteriaType::AccountObtainPetThroughBattle: - case CriteriaType::WinPetBattle: - case CriteriaType::PlayerObtainPetThroughBattle: - case CriteriaType::ActivateGarrisonBuilding: - case CriteriaType::UpgradeGarrison: - case CriteriaType::StartAnyGarrisonMissionWithFollowerType: - case CriteriaType::SucceedAnyGarrisonMissionWithFollowerType: - case CriteriaType::SucceedGarrisonMission: - case CriteriaType::RecruitAnyGarrisonFollower: - case CriteriaType::LearnAnyGarrisonBlueprint: - case CriteriaType::CollectGarrisonShipment: - case CriteriaType::ItemLevelChangedForGarrisonFollower: - case CriteriaType::LevelChangedForGarrisonFollower: - case CriteriaType::LearnToy: - case CriteriaType::LearnAnyToy: - case CriteriaType::FindResearchObject: - case CriteriaType::ExhaustAnyResearchSite: - case CriteriaType::CompleteInternalCriteria: - case CriteriaType::CompleteAnyChallengeMode: - case CriteriaType::KilledAllUnitsInSpawnRegion: - case CriteriaType::CompleteChallengeMode: - case CriteriaType::CreatedItemsByCastingSpellWithLimit: - case CriteriaType::BattlePetAchievementPointsEarned: - case CriteriaType::ReleasedSpirit: - case CriteriaType::AccountKnownPet: - case CriteriaType::KickInitiatorInLFGDungeon: - case CriteriaType::KickVoterInLFGDungeon: - case CriteriaType::KickTargetInLFGDungeon: - case CriteriaType::AbandonedLFGDungeon: - case CriteriaType::GroupedTankLeftEarlyInLFGDungeon: - case CriteriaType::StartGarrisonMission: - case CriteriaType::QualityUpgradedForGarrisonFollower: - case CriteriaType::CompleteResearchGarrisonTalent: - case CriteriaType::RecruitAnyGarrisonTroop: - case CriteriaType::CompleteAnyWorldQuest: - case CriteriaType::ParagonLevelIncreaseWithFaction: - case CriteriaType::PlayerHasEarnedHonor: - case CriteriaType::ChooseRelicTalent: - case CriteriaType::AccountHonorLevelReached: - case CriteriaType::MythicPlusCompleted: - case CriteriaType::SocketAnySoulbindConduit: - case CriteriaType::ObtainAnyItemWithCurrencyValue: - case CriteriaType::EarnExpansionLevel: - case CriteriaType::LearnTransmog: - default: - break; // Not implemented yet :( - } - - for (CriteriaTree const* tree : *trees) - { - if (IsCompletedCriteriaTree(tree)) - CompletedCriteriaTree(tree, referencePlayer); - - AfterCriteriaTreeUpdate(tree, referencePlayer); + break; } + case CriteriaType::UniquePetsOwned: + SetCriteriaProgress(criteria, referencePlayer->GetSession()->GetBattlePetMgr()->GetPetUniqueSpeciesCount(), referencePlayer); + break; + case CriteriaType::GuildAttainedLevel: + SetCriteriaProgress(criteria, miscValue1, referencePlayer); + break; + // FIXME: not triggered in code as result, need to implement + case CriteriaType::RunInstance: + case CriteriaType::EarnTeamArenaRating: + case CriteriaType::EarnTitle: + case CriteriaType::MoneySpentOnGuildRepair: + case CriteriaType::CreatedItemsByCastingSpell: + case CriteriaType::FishInAnyPool: + case CriteriaType::GuildBankTabsPurchased: + case CriteriaType::EarnGuildAchievementPoints: + case CriteriaType::WinAnyBattleground: + case CriteriaType::EarnBattlegroundRating: + case CriteriaType::GuildTabardCreated: + case CriteriaType::CompleteQuestsCountForGuild: + case CriteriaType::HonorableKillsForGuild: + case CriteriaType::KillAnyCreatureForGuild: + case CriteriaType::CompleteAnyResearchProject: + case CriteriaType::CompleteGuildChallenge: + case CriteriaType::CompleteAnyGuildChallenge: + case CriteriaType::CompletedLFRDungeon: + case CriteriaType::AbandonedLFRDungeon: + case CriteriaType::KickInitiatorInLFRDungeon: + case CriteriaType::KickVoterInLFRDungeon: + case CriteriaType::KickTargetInLFRDungeon: + case CriteriaType::GroupedTankLeftEarlyInLFRDungeon: + case CriteriaType::AccountObtainPetThroughBattle: + case CriteriaType::WinPetBattle: + case CriteriaType::PlayerObtainPetThroughBattle: + case CriteriaType::ActivateGarrisonBuilding: + case CriteriaType::UpgradeGarrison: + case CriteriaType::StartAnyGarrisonMissionWithFollowerType: + case CriteriaType::SucceedAnyGarrisonMissionWithFollowerType: + case CriteriaType::SucceedGarrisonMission: + case CriteriaType::RecruitAnyGarrisonFollower: + case CriteriaType::LearnAnyGarrisonBlueprint: + case CriteriaType::CollectGarrisonShipment: + case CriteriaType::ItemLevelChangedForGarrisonFollower: + case CriteriaType::LevelChangedForGarrisonFollower: + case CriteriaType::LearnToy: + case CriteriaType::LearnAnyToy: + case CriteriaType::FindResearchObject: + case CriteriaType::ExhaustAnyResearchSite: + case CriteriaType::CompleteInternalCriteria: + case CriteriaType::CompleteAnyChallengeMode: + case CriteriaType::KilledAllUnitsInSpawnRegion: + case CriteriaType::CompleteChallengeMode: + case CriteriaType::CreatedItemsByCastingSpellWithLimit: + case CriteriaType::BattlePetAchievementPointsEarned: + case CriteriaType::ReleasedSpirit: + case CriteriaType::AccountKnownPet: + case CriteriaType::KickInitiatorInLFGDungeon: + case CriteriaType::KickVoterInLFGDungeon: + case CriteriaType::KickTargetInLFGDungeon: + case CriteriaType::AbandonedLFGDungeon: + case CriteriaType::GroupedTankLeftEarlyInLFGDungeon: + case CriteriaType::StartGarrisonMission: + case CriteriaType::QualityUpgradedForGarrisonFollower: + case CriteriaType::CompleteResearchGarrisonTalent: + case CriteriaType::RecruitAnyGarrisonTroop: + case CriteriaType::CompleteAnyWorldQuest: + case CriteriaType::ParagonLevelIncreaseWithFaction: + case CriteriaType::PlayerHasEarnedHonor: + case CriteriaType::ChooseRelicTalent: + case CriteriaType::AccountHonorLevelReached: + case CriteriaType::MythicPlusCompleted: + case CriteriaType::SocketAnySoulbindConduit: + case CriteriaType::ObtainAnyItemWithCurrencyValue: + case CriteriaType::EarnExpansionLevel: + case CriteriaType::LearnTransmog: + default: + break; // Not implemented yet :( + } + + for (CriteriaTree const* tree : *trees) + { + if (IsCompletedCriteriaTree(tree)) + CompletedCriteriaTree(tree, referencePlayer); + + AfterCriteriaTreeUpdate(tree, referencePlayer); } } diff --git a/src/server/game/Achievements/CriteriaHandler.h b/src/server/game/Achievements/CriteriaHandler.h index 82c8f2ac7d1..067566d0bde 100644 --- a/src/server/game/Achievements/CriteriaHandler.h +++ b/src/server/game/Achievements/CriteriaHandler.h @@ -22,6 +22,7 @@ #include "DBCEnums.h" #include "Duration.h" #include "ObjectGuid.h" +#include <span> #include <unordered_map> #include <vector> #include <ctime> @@ -284,6 +285,7 @@ public: protected: virtual void SendCriteriaUpdate(Criteria const* criteria, CriteriaProgress const* progress, Seconds timeElapsed, bool timedCompleted) const = 0; + void UpdateCriteria(Criteria const* criteria, uint64 miscValue1 = 0, uint64 miscValue2 = 0, uint64 miscValue3 = 0, WorldObject const* ref = nullptr, Player* referencePlayer = nullptr); CriteriaProgress* GetCriteriaProgress(Criteria const* entry); void SetCriteriaProgress(Criteria const* criteria, uint64 changeValue, Player* referencePlayer, ProgressType progressType = PROGRESS_SET); void RemoveCriteriaProgress(Criteria const* criteria); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index f71eba989dd..7ec14e6ac99 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -14892,7 +14892,7 @@ void Player::AddQuest(Quest const* quest, Object* questGiver) GetReputationMgr().SetVisible(factionEntry); break; case QUEST_OBJECTIVE_CRITERIA_TREE: - m_questObjectiveCriteriaMgr->ResetCriteriaTree(obj.ObjectID); + m_questObjectiveCriteriaMgr->ResetCriteriaTree(&obj); break; default: break; diff --git a/src/server/game/Quests/QuestObjectiveCriteriaMgr.cpp b/src/server/game/Quests/QuestObjectiveCriteriaMgr.cpp index 09c29dbac4d..4fe4e246663 100644 --- a/src/server/game/Quests/QuestObjectiveCriteriaMgr.cpp +++ b/src/server/game/Quests/QuestObjectiveCriteriaMgr.cpp @@ -165,9 +165,11 @@ void QuestObjectiveCriteriaMgr::SaveToDB(CharacterDatabaseTransaction trans) } } -void QuestObjectiveCriteriaMgr::ResetCriteriaTree(uint32 criteriaTreeId) +void QuestObjectiveCriteriaMgr::ResetCriteriaTree(QuestObjective const* questObjective) { - CriteriaTree const* tree = sCriteriaMgr->GetCriteriaTree(criteriaTreeId); + _completedObjectives.erase(questObjective->ID); + + CriteriaTree const* tree = sCriteriaMgr->GetCriteriaTree(questObjective->ObjectID); if (!tree) return; @@ -175,6 +177,12 @@ void QuestObjectiveCriteriaMgr::ResetCriteriaTree(uint32 criteriaTreeId) { RemoveCriteriaProgress(criteriaTree->Criteria); }); + + CriteriaMgr::WalkCriteriaTree(tree, [this](CriteriaTree const* criteriaTree) + { + if (criteriaTree->Criteria && advstd::ranges::contains(CriteriaMgr::GetRetroactivelyUpdateableCriteriaTypes(), CriteriaType(criteriaTree->Criteria->Entry->Type))) + UpdateCriteria(criteriaTree->Criteria, 0, 0, 0, nullptr, _owner); + }); } void QuestObjectiveCriteriaMgr::SendAllData(Player const* /*receiver*/) const @@ -210,7 +218,7 @@ void QuestObjectiveCriteriaMgr::CompletedObjective(QuestObjective const* questOb bool QuestObjectiveCriteriaMgr::HasCompletedObjective(QuestObjective const* questObjective) const { - return _completedObjectives.find(questObjective->ID) != _completedObjectives.end(); + return _completedObjectives.contains(questObjective->ID); } void QuestObjectiveCriteriaMgr::SendCriteriaUpdate(Criteria const* criteria, CriteriaProgress const* progress, Seconds timeElapsed, bool timedCompleted) const @@ -293,7 +301,9 @@ void QuestObjectiveCriteriaMgr::CompletedCriteriaTree(CriteriaTree const* tree, if (!objective) return; - CompletedObjective(objective, referencePlayer); + CriteriaTree const* entireObjectiveTree = sCriteriaMgr->GetCriteriaTree(objective->ObjectID); + if (IsCompletedCriteriaTree(entireObjectiveTree)) + CompletedObjective(objective, referencePlayer); } void QuestObjectiveCriteriaMgr::SendPacket(WorldPacket const* data) const diff --git a/src/server/game/Quests/QuestObjectiveCriteriaMgr.h b/src/server/game/Quests/QuestObjectiveCriteriaMgr.h index f3ba31c2ac1..f38c456539b 100644 --- a/src/server/game/Quests/QuestObjectiveCriteriaMgr.h +++ b/src/server/game/Quests/QuestObjectiveCriteriaMgr.h @@ -35,7 +35,7 @@ public: void LoadFromDB(PreparedQueryResult objectiveResult, PreparedQueryResult criteriaResult); void SaveToDB(CharacterDatabaseTransaction trans); - void ResetCriteriaTree(uint32 criteriaTreeId); + void ResetCriteriaTree(QuestObjective const* questObjective); void SendAllData(Player const* receiver) const override; |