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)
This commit is contained in:
Shauren
2024-12-08 00:23:38 +01:00
parent 6da1679cbf
commit 4e89a302fc
5 changed files with 381 additions and 366 deletions

View File

@@ -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;
// requirements not found in the dbc
if (CriteriaDataSet const* data = sCriteriaMgr->GetCriteriaDataSet(criteria))
if (!data->Meets(referencePlayer, ref, uint32(miscValue1), uint32(miscValue2)))
continue;
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, 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:
{
// 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:
time_t nextDailyResetTime = sWorld->GetNextDailyQuestsResetTime();
CriteriaProgress *progress = GetCriteriaProgress(criteria);
if (!miscValue1) // Login case.
{
// reset if player missed one day.
if (progress && progress->Date < (nextDailyResetTime - 2 * DAY))
SetCriteriaProgress(criteria, 0, referencePlayer, PROGRESS_SET);
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;
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:
}
else // login case
{
uint32 counter = 0;
RewardedQuestSet const& rewQuests = referencePlayer->getRewardedQuests();
for (uint32 rewQuest : rewQuests)
{
Quest const* quest = sObjectMgr->GetQuestTemplate(rewQuest);
if (quest && quest->GetZoneOrSort() >= 0 && quest->GetZoneOrSort() == criteria->Entry->Asset.ZoneID)
++counter;
}
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:
{
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())
{
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)
return;
SetCriteriaProgress(criteria, miscValue1, referencePlayer, PROGRESS_ACCUMULATE);
break;
case CriteriaType::EarnPersonalArenaRating:
{
uint32 reqTeamType = criteria->Entry->Asset.TeamType;
if (miscValue1)
{
if (miscValue2 != reqTeamType)
return;
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);
if (!miscValue1) // Login case.
{
// reset if player missed one day.
if (progress && progress->Date < (nextDailyResetTime - 2 * DAY))
SetCriteriaProgress(criteria, 0, referencePlayer, PROGRESS_SET);
continue;
}
ProgressType progressType;
if (!progress)
// 1st time. Start count.
progressType = PROGRESS_SET;
else if (progress->Date < (nextDailyResetTime - 2 * DAY))
// last progress is older than 2 days. Player missed 1 day => Restart count.
progressType = PROGRESS_SET;
else if (progress->Date < (nextDailyResetTime - DAY))
// last progress is between 1 and 2 days. => 1st time of the day.
progressType = PROGRESS_ACCUMULATE;
else
// last progress is within the day before the reset => Already counted today.
continue;
SetCriteriaProgress(criteria, 1, referencePlayer, progressType);
break;
}
case CriteriaType::CompleteQuestsInZone:
else // login case
{
if (miscValue1)
for (uint8 arena_slot = 0; arena_slot < MAX_ARENA_SLOT; ++arena_slot)
{
SetCriteriaProgress(criteria, 1, referencePlayer, PROGRESS_ACCUMULATE);
}
else // login case
{
uint32 counter = 0;
RewardedQuestSet const& rewQuests = referencePlayer->getRewardedQuests();
for (uint32 rewQuest : rewQuests)
{
Quest const* quest = sObjectMgr->GetQuestTemplate(rewQuest);
if (quest && quest->GetZoneOrSort() >= 0 && quest->GetZoneOrSort() == criteria->Entry->Asset.ZoneID)
++counter;
}
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:
{
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())
{
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;
if (miscValue1)
{
if (miscValue2 != reqTeamType)
uint32 teamId = referencePlayer->GetArenaTeamId(arena_slot);
if (!teamId)
continue;
SetCriteriaProgress(criteria, miscValue1, referencePlayer, PROGRESS_HIGHEST);
}
else // login case
{
for (uint8 arena_slot = 0; arena_slot < MAX_ARENA_SLOT; ++arena_slot)
ArenaTeam* team = sArenaTeamMgr->GetArenaTeamById(teamId);
if (!team || team->GetType() != reqTeamType)
continue;
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 :(
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);
for (CriteriaTree const* tree : *trees)
{
if (IsCompletedCriteriaTree(tree))
CompletedCriteriaTree(tree, referencePlayer);
AfterCriteriaTreeUpdate(tree, referencePlayer);
}
AfterCriteriaTreeUpdate(tree, referencePlayer);
}
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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

View File

@@ -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;