using System; using System.Collections.Generic; using System.Linq; using Dalamud.Plugin.Services; using Lumina.Excel; using Lumina.Excel.Sheets; namespace QuestionableCompanion.Services; public class EventQuestResolver { private readonly IDataManager dataManager; private readonly IPluginLog log; public EventQuestResolver(IDataManager dataManager, IPluginLog log) { this.dataManager = dataManager; this.log = log; } public List ResolveEventQuestDependencies(string eventQuestId) { List dependencies = new List(); ExcelSheet questSheet = dataManager.GetExcelSheet(); log.Information("[EventQuestResolver] Searching for quest with ID string: '" + eventQuestId + "'"); Quest? foundQuest = null; foreach (Quest q in questSheet) { if (q.RowId != 0) { string questIdField = q.Id.ExtractText(); if (questIdField == eventQuestId || questIdField.EndsWith("_" + eventQuestId) || questIdField.EndsWith("_" + eventQuestId.PadLeft(5, '0'))) { foundQuest = q; log.Information($"[EventQuestResolver] Found quest by ID field: '{questIdField}' (searched for '{eventQuestId}')"); break; } } } if (!foundQuest.HasValue || foundQuest.Value.RowId == 0) { log.Error("[EventQuestResolver] Quest with ID '" + eventQuestId + "' not found in Lumina"); return dependencies; } Quest quest = foundQuest.Value; string questName = quest.Name.ExtractText(); log.Information($"[EventQuestResolver] Found quest: RowId={quest.RowId}, Name='{questName}', ID='{quest.Id.ExtractText()}'"); try { foreach (RowRef prevQuestRef in quest.PreviousQuest) { if (prevQuestRef.RowId == 0) { continue; } Quest prevQuest = questSheet.GetRow(prevQuestRef.RowId); if (prevQuest.RowId != 0) { string prevQuestName = prevQuest.Name.ExtractText(); string prevQuestIdString = prevQuest.Id.ExtractText(); string[] idParts = prevQuestIdString.Split('_'); string questIdNumber = ((idParts.Length > 1) ? idParts[1].TrimStart('0') : prevQuestIdString); if (string.IsNullOrEmpty(questIdNumber)) { questIdNumber = "0"; } dependencies.Add(questIdNumber); log.Information($"[EventQuestResolver] Found previous quest: RowId={prevQuestRef.RowId}, Name='{prevQuestName}', ID='{prevQuestIdString}' -> '{questIdNumber}'"); } } } catch (Exception ex) { log.Warning("[EventQuestResolver] Error reading PreviousQuest: " + ex.Message); } try { foreach (RowRef questLockRef in quest.QuestLock) { if (questLockRef.RowId == 0) { continue; } Quest lockQuest = questSheet.GetRow(questLockRef.RowId); if (lockQuest.RowId != 0) { string lockQuestIdString = lockQuest.Id.ExtractText(); string[] idParts2 = lockQuestIdString.Split('_'); string questIdNumber2 = ((idParts2.Length > 1) ? idParts2[1].TrimStart('0') : lockQuestIdString); if (string.IsNullOrEmpty(questIdNumber2)) { questIdNumber2 = "0"; } dependencies.Add(questIdNumber2); log.Information($"[EventQuestResolver] Found quest lock: RowId={questLockRef.RowId}, ID='{lockQuestIdString}' -> '{questIdNumber2}'"); } } } catch (Exception ex2) { log.Warning("[EventQuestResolver] Error reading QuestLock: " + ex2.Message); } dependencies = dependencies.Distinct().ToList(); log.Information($"[EventQuestResolver] Found {dependencies.Count} direct prerequisites"); if (dependencies.Count > 0) { log.Information("[EventQuestResolver] Event Quest " + eventQuestId + " requires: " + string.Join(", ", dependencies)); } else { log.Information("[EventQuestResolver] Event Quest " + eventQuestId + " has no prerequisites"); } return dependencies; } public bool IsValidQuest(string questId, out string classification) { string rawId = QuestIdParser.ParseQuestId(questId).rawId; if (QuestIdParser.ClassifyQuestId(questId) == QuestIdType.EventQuest) { classification = "EventQuest"; log.Debug("[EventQuestResolver] Quest " + questId + " recognized as Event Quest (prefix detected)"); return true; } if (!uint.TryParse(rawId, out var questIdUint)) { classification = "Invalid"; return false; } try { Quest quest = dataManager.GetExcelSheet().GetRow(questIdUint); if (quest.RowId != 0) { classification = "Standard"; log.Debug($"[EventQuestResolver] Quest {questId} found in Excel Sheet (RowId: {quest.RowId})"); return true; } classification = "NotFound"; return false; } catch (Exception ex) { log.Debug("[EventQuestResolver] Error checking quest availability: " + ex.Message); classification = "Error"; return false; } } public bool IsQuestAvailable(string questId) { string classification; return IsValidQuest(questId, out classification); } public string GetQuestName(string questId) { string rawId = QuestIdParser.ParseQuestId(questId).rawId; QuestIdType questType = QuestIdParser.ClassifyQuestId(questId); if (!uint.TryParse(rawId, out var questIdUint)) { if (questType == QuestIdType.EventQuest) { return "Event Quest " + questId; } return "Unknown Quest (" + questId + ")"; } try { Quest quest = dataManager.GetExcelSheet().GetRow(questIdUint); if (quest.RowId != 0) { string name = quest.Name.ExtractText(); if (!string.IsNullOrEmpty(name)) { if (questType == QuestIdType.EventQuest) { return name + " (" + questId + ")"; } return name; } } if (questType == QuestIdType.EventQuest) { return "Event Quest " + questId; } return "Quest " + questId; } catch (Exception) { if (questType == QuestIdType.EventQuest) { return "Event Quest " + questId; } return "Quest " + questId; } } public List<(string QuestId, string QuestName)> GetAvailableEventQuests() { List<(string, string)> eventQuests = new List<(string, string)>(); try { ExcelSheet questSheet = dataManager.GetExcelSheet(); if (questSheet == null) { log.Error("[EventQuestResolver] Failed to load Quest sheet"); return eventQuests; } foreach (Quest quest in questSheet) { if (quest.RowId != 0 && quest.JournalGenre.RowId == 9) { string questName = quest.Name.ExtractText(); if (!string.IsNullOrEmpty(questName)) { eventQuests.Add((quest.RowId.ToString(), questName)); } } } log.Information($"[EventQuestResolver] Found {eventQuests.Count} event quests"); } catch (Exception ex) { log.Error("[EventQuestResolver] Error getting event quests: " + ex.Message); } return eventQuests.OrderBy(((string, string) q) => q.Item2).ToList(); } }