Core support for breadcrumb quests

Port From (https://github.com/TrinityCore/TrinityCore/commit/0bde06c4027d2e60edc30b55fa7b42da8d253d29)
This commit is contained in:
hondacrx
2021-12-01 10:19:39 -05:00
parent 334720dafe
commit 8d8479b49e
4 changed files with 452 additions and 28 deletions
+45 -1
View File
@@ -1338,7 +1338,8 @@ namespace Game.Entities
public bool SatisfyQuestDependentQuests(Quest qInfo, bool msg)
{
return SatisfyQuestPreviousQuest(qInfo, msg) && SatisfyQuestDependentPreviousQuests(qInfo, msg);
return SatisfyQuestPreviousQuest(qInfo, msg) && SatisfyQuestDependentPreviousQuests(qInfo, msg) &&
SatisfyQuestBreadcrumbQuest(qInfo, msg) && SatisfyQuestDependentBreadcrumbQuests(qInfo, msg);
}
public bool SatisfyQuestPreviousQuest(Quest qInfo, bool msg)
@@ -1421,6 +1422,49 @@ namespace Game.Entities
return false;
}
bool SatisfyQuestBreadcrumbQuest(Quest qInfo, bool msg)
{
uint breadcrumbTargetQuestId = (uint)Math.Abs(qInfo.BreadcrumbForQuestId);
//If this is not a breadcrumb quest.
if (breadcrumbTargetQuestId == 0)
return true;
// If the target quest is not available
if (!CanTakeQuest(Global.ObjectMgr.GetQuestTemplate(breadcrumbTargetQuestId), false))
{
if (msg)
{
SendCanTakeQuestResponse(QuestFailedReasons.None);
Log.outDebug(LogFilter.Misc, $"Player.SatisfyQuestBreadcrumbQuest: Sent INVALIDREASON_DONT_HAVE_REQ (QuestID: {qInfo.Id}) because target quest (QuestID: {breadcrumbTargetQuestId}) is not available to player '{GetName()}' ({GetGUID()}).");
}
return false;
}
return true;
}
bool SatisfyQuestDependentBreadcrumbQuests(Quest qInfo, bool msg)
{
foreach (uint breadcrumbQuestId in qInfo.DependentBreadcrumbQuests)
{
QuestStatus status = GetQuestStatus(breadcrumbQuestId);
// If any of the breadcrumb quests are in the quest log, return false.
if (status == QuestStatus.Incomplete || status == QuestStatus.Complete || status == QuestStatus.Failed)
{
if (msg)
{
SendCanTakeQuestResponse(QuestFailedReasons.None);
Log.outDebug(LogFilter.Misc, $"Player.SatisfyQuestDependentBreadcrumbQuests: Sent INVALIDREASON_DONT_HAVE_REQ (QuestID: {qInfo.Id}) because player '{GetName()}' ({GetGUID()}) has a breadcrumb quest towards this quest in the quest log.");
}
return false;
}
}
return true;
}
public bool SatisfyQuestClass(Quest qInfo, bool msg)
{
uint reqClass = qInfo.AllowableClasses;
+52 -2
View File
@@ -7544,8 +7544,11 @@ namespace Game
// fill additional data stores
if (qinfo.PrevQuestId != 0)
{
if (!_questTemplates.ContainsKey((uint)Math.Abs(qinfo.PrevQuestId)))
Log.outError(LogFilter.Sql, "Quest {0} has PrevQuestId {1}, but no such quest", qinfo.Id, qinfo.PrevQuestId);
var prevQuestItr = _questTemplates.LookupByKey(qinfo.PrevQuestId);
if (prevQuestItr == null)
Log.outError(LogFilter.Sql, $"Quest {qinfo.Id} has PrevQuestId {qinfo.PrevQuestId}, but no such quest");
else if (prevQuestItr.BreadcrumbForQuestId != 0)
Log.outError(LogFilter.Sql, $"Quest {qinfo.Id} should not be unlocked by breadcrumb quest {qinfo.PrevQuestId}");
}
if (qinfo.NextQuestId != 0)
@@ -7557,10 +7560,57 @@ namespace Game
nextquest.DependentPreviousQuests.Add(qinfo.Id);
}
uint breadcrumbForQuestId = (uint)Math.Abs(qinfo.BreadcrumbForQuestId);
if (breadcrumbForQuestId != 0)
{
if (!_questTemplates.ContainsKey(breadcrumbForQuestId))
{
Log.outError(LogFilter.Sql, $"Quest {qinfo.Id} is a breadcrumb for quest {breadcrumbForQuestId}, but no such quest exists");
qinfo.BreadcrumbForQuestId = 0;
}
if (qinfo.NextQuestId != 0)
Log.outError(LogFilter.Sql, $"Quest {qinfo.Id} is a breadcrumb, should not unlock quest {qinfo.NextQuestId}");
if (qinfo.ExclusiveGroup != 0)
Log.outError(LogFilter.Sql, $"Quest {qinfo.Id} is a breadcrumb in exclusive group {qinfo.ExclusiveGroup}");
}
if (qinfo.ExclusiveGroup != 0)
_exclusiveQuestGroups.Add(qinfo.ExclusiveGroup, qinfo.Id);
}
foreach (var questPair in _questTemplates)
{
// skip post-loading checks for disabled quests
if (Global.DisableMgr.IsDisabledFor(DisableType.Quest, questPair.Key, null))
continue;
Quest qinfo = questPair.Value;
uint qid = qinfo.Id;
uint breadcrumbForQuestId = (uint)Math.Abs(qinfo.BreadcrumbForQuestId);
List<uint> questSet = new();
while (breadcrumbForQuestId != 0)
{
//a previously visited quest was found as a breadcrumb quest
//breadcrumb loop found!
if (questSet.Contains(qinfo.Id))
{
Log.outError(LogFilter.Sql, $"Breadcrumb quests {qid} and {breadcrumbForQuestId} are in a loop");
qinfo.BreadcrumbForQuestId = 0;
break;
}
questSet.Add(qinfo.Id);
qinfo = Global.ObjectMgr.GetQuestTemplate(breadcrumbForQuestId);
//every quest has a list of every breadcrumb towards it
qinfo.DependentBreadcrumbQuests.Add(qid);
breadcrumbForQuestId = (uint)Math.Abs(qinfo.BreadcrumbForQuestId);
}
}
// check QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT for spell with SPELL_EFFECT_QUEST_COMPLETE
foreach (SpellNameRecord spellNameEntry in CliDB.SpellNameStorage.Values)
{
+28 -25
View File
@@ -218,17 +218,18 @@ namespace Game
PrevQuestId = fields.Read<int>(4);
NextQuestId = fields.Read<uint>(5);
ExclusiveGroup = fields.Read<int>(6);
RewardMailTemplateId = fields.Read<uint>(7);
RewardMailDelay = fields.Read<uint>(8);
RequiredSkillId = fields.Read<ushort>(9);
RequiredSkillPoints = fields.Read<ushort>(10);
RequiredMinRepFaction = fields.Read<ushort>(11);
RequiredMaxRepFaction = fields.Read<ushort>(12);
RequiredMinRepValue = fields.Read<int>(13);
RequiredMaxRepValue = fields.Read<int>(14);
SourceItemIdCount = fields.Read<byte>(15);
SpecialFlags = (QuestSpecialFlags)fields.Read<byte>(16);
ScriptId = Global.ObjectMgr.GetScriptId(fields.Read<string>(17));
BreadcrumbForQuestId = fields.Read<int>(7);
RewardMailTemplateId = fields.Read<uint>(8);
RewardMailDelay = fields.Read<uint>(9);
RequiredSkillId = fields.Read<ushort>(10);
RequiredSkillPoints = fields.Read<ushort>(11);
RequiredMinRepFaction = fields.Read<ushort>(12);
RequiredMaxRepFaction = fields.Read<ushort>(13);
RequiredMinRepValue = fields.Read<int>(14);
RequiredMaxRepValue = fields.Read<int>(15);
SourceItemIdCount = fields.Read<byte>(16);
SpecialFlags = (QuestSpecialFlags)fields.Read<byte>(17);
ScriptId = Global.ObjectMgr.GetScriptId(fields.Read<string>(18));
if (SpecialFlags.HasAnyFlag(QuestSpecialFlags.AutoAccept))
Flags |= QuestFlags.AutoAccept;
@@ -699,27 +700,29 @@ namespace Game
public string OfferRewardText = "";
// quest_template_addon table (custom data)
public uint MaxLevel;
public uint MaxLevel { get; set; }
public uint AllowableClasses { get; set; }
public uint SourceSpellID { get; set; }
public int PrevQuestId;
public uint NextQuestId;
public int ExclusiveGroup;
public int PrevQuestId { get; set; }
public uint NextQuestId { get; set; }
public int ExclusiveGroup { get; set; }
public int BreadcrumbForQuestId { get; set; }
public uint RewardMailTemplateId { get; set; }
public uint RewardMailDelay { get; set; }
public uint RequiredSkillId;
public uint RequiredSkillPoints;
public uint RequiredMinRepFaction;
public int RequiredMinRepValue;
public uint RequiredMaxRepFaction;
public int RequiredMaxRepValue;
public uint SourceItemIdCount;
public uint RewardMailSenderEntry;
public QuestSpecialFlags SpecialFlags; // custom flags, not sniffed/WDB
public uint RequiredSkillId { get; set; }
public uint RequiredSkillPoints { get; set; }
public uint RequiredMinRepFaction { get; set; }
public int RequiredMinRepValue { get; set; }
public uint RequiredMaxRepFaction { get; set; }
public int RequiredMaxRepValue { get; set; }
public uint SourceItemIdCount { get; set; }
public uint RewardMailSenderEntry { get; set; }
public QuestSpecialFlags SpecialFlags { get; set; } // custom flags, not sniffed/WDB
public BitArray _usedQuestObjectiveTypes = new((int)QuestObjectiveType.Max);
public uint ScriptId;
public uint ScriptId { get; set; }
public List<uint> DependentPreviousQuests = new();
public List<uint> DependentBreadcrumbQuests = new();
public QueryQuestInfoResponse QueryData;
uint _rewChoiceItemsCount;