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)
Port From (https://github.com/TrinityCore/TrinityCore/commit/4e89a302fcce7644bcd8cf239edad3b409950438)
This commit is contained in:
Hondacrx
2025-02-24 11:21:04 -05:00
parent 0d5c0b572d
commit 0e050f6c54
3 changed files with 795 additions and 779 deletions
+29 -24
View File
@@ -70,18 +70,21 @@ namespace Game.Achievements
List<Criteria> criteriaList = GetCriteriaByType(type, (uint)miscValue1); List<Criteria> criteriaList = GetCriteriaByType(type, (uint)miscValue1);
foreach (Criteria criteria in criteriaList) foreach (Criteria criteria in criteriaList)
UpdateCriteria(criteria, miscValue1, miscValue2, miscValue3, refe, referencePlayer);
}
public void UpdateCriteria(Criteria criteria, ulong miscValue1 = 0, ulong miscValue2 = 0, ulong miscValue3 = 0, WorldObject refe = null, Player referencePlayer = null)
{ {
List<CriteriaTree> trees = Global.CriteriaMgr.GetCriteriaTreesByCriteria(criteria.Id); var trees = Global.CriteriaMgr.GetCriteriaTreesByCriteria(criteria.Id);
if (!CanUpdateCriteria(criteria, trees, miscValue1, miscValue2, miscValue3, refe, referencePlayer)) if (!CanUpdateCriteria(criteria, trees, miscValue1, miscValue2, miscValue3, refe, referencePlayer))
continue; return;
// requirements not found in the dbc // requirements not found in the dbc
CriteriaDataSet data = Global.CriteriaMgr.GetCriteriaDataSet(criteria); CriteriaDataSet data = Global.CriteriaMgr.GetCriteriaDataSet(criteria);
if (data != null) if (data != null && !data.Meets(referencePlayer, refe, (uint)miscValue1, (uint)miscValue2))
if (!data.Meets(referencePlayer, refe, (uint)miscValue1, (uint)miscValue2)) return;
continue;
switch (type) switch (criteria.Entry.Type)
{ {
// std. case: increment at 1 // std. case: increment at 1
case CriteriaType.WinBattleground: case CriteriaType.WinBattleground:
@@ -123,7 +126,7 @@ namespace Game.Achievements
case CriteriaType.KillPlayer: case CriteriaType.KillPlayer:
case CriteriaType.DeliveredKillingBlow: case CriteriaType.DeliveredKillingBlow:
case CriteriaType.PVPKillInArea: case CriteriaType.PVPKillInArea:
case CriteriaType.WinArena: // This also behaves like CriteriaType.WinAnyRankedArena case CriteriaType.WinArena: // This also behaves like CriteriaType::WinAnyRankedArena
case CriteriaType.ParticipateInArena: case CriteriaType.ParticipateInArena:
case CriteriaType.PlayerTriggerGameEvent: case CriteriaType.PlayerTriggerGameEvent:
case CriteriaType.Login: case CriteriaType.Login:
@@ -202,7 +205,7 @@ namespace Game.Achievements
SetCriteriaProgress(criteria, maxSkillvalue, referencePlayer); SetCriteriaProgress(criteria, maxSkillvalue, referencePlayer);
break; break;
case CriteriaType.CompleteQuestsCount: case CriteriaType.CompleteQuestsCount:
SetCriteriaProgress(criteria, (uint)referencePlayer.GetRewardedQuestCount(), referencePlayer); SetCriteriaProgress(criteria, (ulong)referencePlayer.GetRewardedQuestCount(), referencePlayer);
break; break;
case CriteriaType.CompleteAnyDailyQuestPerDay: case CriteriaType.CompleteAnyDailyQuestPerDay:
{ {
@@ -213,8 +216,8 @@ namespace Game.Achievements
{ {
// reset if player missed one day. // reset if player missed one day.
if (progress != null && progress.Date < (nextDailyResetTime - 2 * Time.Day)) if (progress != null && progress.Date < (nextDailyResetTime - 2 * Time.Day))
SetCriteriaProgress(criteria, 0, referencePlayer); SetCriteriaProgress(criteria, 0, referencePlayer, ProgressType.Set);
continue; return;
} }
ProgressType progressType; ProgressType progressType;
@@ -229,7 +232,7 @@ namespace Game.Achievements
progressType = ProgressType.Accumulate; progressType = ProgressType.Accumulate;
else else
// last progress is within the day before the reset => Already counted today. // last progress is within the day before the reset => Already counted today.
continue; return;
SetCriteriaProgress(criteria, 1, referencePlayer, progressType); SetCriteriaProgress(criteria, 1, referencePlayer, progressType);
break; break;
@@ -245,13 +248,14 @@ namespace Game.Achievements
uint counter = 0; uint counter = 0;
var rewQuests = referencePlayer.GetRewardedQuests(); var rewQuests = referencePlayer.GetRewardedQuests();
foreach (var id in rewQuests) foreach (uint rewQuest in rewQuests)
{ {
Quest quest = Global.ObjectMgr.GetQuestTemplate(id); Quest quest = Global.ObjectMgr.GetQuestTemplate(rewQuest);
if (quest != null && quest.QuestSortID >= 0 && quest.QuestSortID == criteria.Entry.Asset) if (quest != null && quest.QuestSortID >= 0 && quest.QuestSortID == criteria.Entry.Asset)
++counter; ++counter;
} }
SetCriteriaProgress(criteria, counter, referencePlayer);
SetCriteriaProgress(criteria, counter, referencePlayer, ProgressType.Highest);
} }
break; break;
} }
@@ -286,7 +290,7 @@ namespace Game.Achievements
{ {
int reputation = referencePlayer.GetReputationMgr().GetReputation(criteria.Entry.Asset); int reputation = referencePlayer.GetReputationMgr().GetReputation(criteria.Entry.Asset);
if (reputation > 0) if (reputation > 0)
SetCriteriaProgress(criteria, (uint)reputation, referencePlayer); SetCriteriaProgress(criteria, (ulong)reputation, referencePlayer);
break; break;
} }
case CriteriaType.TotalExaltedFactions: case CriteriaType.TotalExaltedFactions:
@@ -299,9 +303,9 @@ namespace Game.Achievements
foreach (var (spellId, _) in referencePlayer.GetSpellMap()) foreach (var (spellId, _) in referencePlayer.GetSpellMap())
{ {
var bounds = Global.SpellMgr.GetSkillLineAbilityMapBounds(spellId); var bounds = Global.SpellMgr.GetSkillLineAbilityMapBounds(spellId);
foreach (var skill in bounds) foreach (var skillLineRecord in bounds)
{ {
if (skill.SkillLine == criteria.Entry.Asset) if (skillLineRecord.SkillLine == criteria.Entry.Asset)
{ {
// do not add couter twice if by any chance skill is listed twice in dbc (eg. skill 777 and spell 22717) // do not add couter twice if by any chance skill is listed twice in dbc (eg. skill 777 and spell 22717)
++spellCount; ++spellCount;
@@ -309,6 +313,7 @@ namespace Game.Achievements
} }
} }
} }
SetCriteriaProgress(criteria, spellCount, referencePlayer); SetCriteriaProgress(criteria, spellCount, referencePlayer);
break; break;
} }
@@ -329,7 +334,7 @@ namespace Game.Achievements
break; break;
case CriteriaType.EarnAchievementPoints: case CriteriaType.EarnAchievementPoints:
if (miscValue1 == 0) if (miscValue1 == 0)
continue; return;
SetCriteriaProgress(criteria, miscValue1, referencePlayer, ProgressType.Accumulate); SetCriteriaProgress(criteria, miscValue1, referencePlayer, ProgressType.Accumulate);
break; break;
case CriteriaType.EarnPersonalArenaRating: case CriteriaType.EarnPersonalArenaRating:
@@ -339,13 +344,12 @@ namespace Game.Achievements
if (miscValue1 != 0) if (miscValue1 != 0)
{ {
if (miscValue2 != reqTeamType) if (miscValue2 != reqTeamType)
continue; return;
SetCriteriaProgress(criteria, miscValue1, referencePlayer, ProgressType.Highest); SetCriteriaProgress(criteria, miscValue1, referencePlayer, ProgressType.Highest);
} }
else // login case else // login case
{ {
for (byte arena_slot = 0; arena_slot < SharedConst.MaxArenaSlot; ++arena_slot) for (byte arena_slot = 0; arena_slot < SharedConst.MaxArenaSlot; ++arena_slot)
{ {
uint teamId = referencePlayer.GetArenaTeamId(arena_slot); uint teamId = referencePlayer.GetArenaTeamId(arena_slot);
@@ -363,6 +367,7 @@ namespace Game.Achievements
break; break;
} }
} }
} }
break; break;
} }
@@ -440,6 +445,7 @@ namespace Game.Achievements
case CriteriaType.ObtainAnyItemWithCurrencyValue: case CriteriaType.ObtainAnyItemWithCurrencyValue:
case CriteriaType.EarnExpansionLevel: case CriteriaType.EarnExpansionLevel:
case CriteriaType.LearnTransmog: case CriteriaType.LearnTransmog:
default:
break; // Not implemented yet :( break; // Not implemented yet :(
} }
@@ -451,7 +457,6 @@ namespace Game.Achievements
AfterCriteriaTreeUpdate(tree, referencePlayer); AfterCriteriaTreeUpdate(tree, referencePlayer);
} }
} }
}
public void UpdateTimedCriteria(TimeSpan timeDiff) public void UpdateTimedCriteria(TimeSpan timeDiff)
{ {
@@ -3769,7 +3774,7 @@ namespace Game.Achievements
} }
public class CriteriaManager : Singleton<CriteriaManager> public class CriteriaManager : Singleton<CriteriaManager>
{ {
Dictionary<uint, CriteriaDataSet> _criteriaDataMap = new(); Dictionary<uint, CriteriaDataSet> _criteriaDataMap = new();
Dictionary<uint, CriteriaTree> _criteriaTrees = new(); Dictionary<uint, CriteriaTree> _criteriaTrees = new();
@@ -4280,9 +4285,9 @@ namespace Game.Achievements
func(tree); func(tree);
} }
} }
public class ModifierTreeNode public class ModifierTreeNode
{ {
public ModifierTreeRecord Entry; public ModifierTreeRecord Entry;
public List<ModifierTreeNode> Children = new(); public List<ModifierTreeNode> Children = new();
+1 -1
View File
@@ -785,7 +785,7 @@ namespace Game.Entities
GetReputationMgr().SetVisible(factionEntry); GetReputationMgr().SetVisible(factionEntry);
break; break;
case QuestObjectiveType.CriteriaTree: case QuestObjectiveType.CriteriaTree:
m_questObjectiveCriteriaMgr.ResetCriteriaTree((uint)obj.ObjectID); m_questObjectiveCriteriaMgr.ResetCriteriaTree(obj);
break; break;
default: default:
break; break;
@@ -9,6 +9,7 @@ using Game.Networking;
using Game.Networking.Packets; using Game.Networking.Packets;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
namespace Game namespace Game
{ {
@@ -150,9 +151,11 @@ namespace Game
} }
} }
public void ResetCriteriaTree(uint criteriaTreeId) public void ResetCriteriaTree(QuestObjective questObjective)
{ {
CriteriaTree tree = Global.CriteriaMgr.GetCriteriaTree(criteriaTreeId); _completedObjectives.Remove(questObjective.Id);
CriteriaTree tree = Global.CriteriaMgr.GetCriteriaTree((uint)questObjective.ObjectID);
if (tree == null) if (tree == null)
return; return;
@@ -160,6 +163,12 @@ namespace Game
{ {
RemoveCriteriaProgress(criteriaTree.Criteria); RemoveCriteriaProgress(criteriaTree.Criteria);
}); });
CriteriaManager.WalkCriteriaTree(tree, criteriaTree =>
{
if (criteriaTree.Criteria != null && CriteriaManager.GetRetroactivelyUpdateableCriteriaTypes().Contains(criteriaTree.Criteria.Entry.Type))
UpdateCriteria(criteriaTree.Criteria, 0, 0, 0, null, _owner);
});
} }
public override void SendAllData(Player receiver) public override void SendAllData(Player receiver)
@@ -274,6 +283,8 @@ namespace Game
if (objective == null) if (objective == null)
return; return;
CriteriaTree entireObjectiveTree = Global.CriteriaMgr.GetCriteriaTree((uint)objective.ObjectID);
if (IsCompletedCriteriaTree(entireObjectiveTree))
CompletedObjective(objective, referencePlayer); CompletedObjective(objective, referencePlayer);
} }