Core support for breadcrumb quests
Port From (https://github.com/TrinityCore/TrinityCore/commit/0bde06c4027d2e60edc30b55fa7b42da8d253d29)
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user