using UnityEngine; using System.Collections.Generic; using System.Linq; using UnityEngine.Events; using TMPro; /// /// Centralized manager for all quests in the game /// Handles quest state transitions and tracking /// public class QuestManager : MonoBehaviour { // Singleton instance public static QuestManager Instance { get; private set; } [Header("UI")] [SerializeField] private TextMeshProUGUI currentQuestTitleText; [SerializeField] private TextMeshProUGUI currentQuestDescriptionText; [Header("Quest Database")] [Tooltip("All available quests in the game")] public List availableQuests = new List(); [Header("Runtime Quest Tracking")] [SerializeField] private List activeQuests = new List(); [SerializeField] private List completedQuests = new List(); [SerializeField] private List failedQuests = new List(); [Header("Events")] public UnityEvent onQuestStarted; public UnityEvent onQuestProgressed; public UnityEvent onQuestCompleted; public UnityEvent onQuestFailed; void Awake() { // Singleton pattern if (Instance != null && Instance != this) { Debug.LogWarning("Multiple QuestManager instances detected. Destroying duplicate.", gameObject); Destroy(this); return; } Instance = this; } void OnDestroy() { if (Instance == this) Instance = null; } void Start() { UpdateQuestUIFromCurrent(); } /// /// Start a quest by ID /// public bool StartQuest(string questId) { Quest quest = GetQuestById(questId); if (quest == null) { Debug.LogWarning($"Quest '{questId}' not found in available quests."); return false; } return StartQuest(quest); } /// /// Start a quest /// public bool StartQuest(Quest quest) { if (quest == null) { Debug.LogWarning("Cannot start null quest."); return false; } // Check if already active if (activeQuests.Contains(quest)) { Debug.Log($"Quest '{quest.questName}' is already active."); return false; } // Check if can start if (!quest.CanStart()) { Debug.Log($"Quest '{quest.questName}' cannot be started (current state: {quest.state})."); return false; } // Check prerequisites if (!string.IsNullOrEmpty(quest.prerequisiteQuestId)) { Quest prerequisite = GetQuestById(quest.prerequisiteQuestId); if (prerequisite != null && prerequisite.state != QuestState.Completed) { Debug.Log($"Quest '{quest.questName}' requires completing '{prerequisite.questName}' first."); return false; } } // Start the quest quest.state = QuestState.Active; quest.currentProgress = 0; activeQuests.Add(quest); Debug.Log($"Quest Started: {quest.questName}"); onQuestStarted?.Invoke(quest); UpdateQuestUI(quest); return true; } /// /// Progress a quest by ID /// public bool ProgressQuest(string questId, int amount = 1) { Quest quest = GetActiveQuest(questId); if (quest == null) { Debug.LogWarning($"Active quest '{questId}' not found."); return false; } return ProgressQuest(quest, amount); } /// /// Progress a quest /// public bool ProgressQuest(Quest quest, int amount = 1) { if (quest == null || !quest.IsActive()) { Debug.LogWarning("Cannot progress quest - not active."); return false; } int previousProgress = quest.currentProgress; quest.AddProgress(amount); if (quest.currentProgress > previousProgress) { Debug.Log($"Quest Progress: {quest.questName} ({quest.currentProgress}/{quest.requiredProgress})"); onQuestProgressed?.Invoke(quest); UpdateQuestUI(quest); return true; } return false; } /// /// Complete a quest by ID /// public bool CompleteQuest(string questId) { Quest quest = GetActiveQuest(questId); if (quest == null) { Debug.LogWarning($"Active quest '{questId}' not found."); return false; } return CompleteQuest(quest); } /// /// Complete a quest and grant rewards /// public bool CompleteQuest(Quest quest) { if (quest == null) { Debug.LogWarning("Cannot complete null quest."); return false; } if (!quest.IsComplete()) { Debug.Log($"Quest '{quest.questName}' objectives not met ({quest.currentProgress}/{quest.requiredProgress})."); return false; } // Remove from active, add to completed activeQuests.Remove(quest); quest.state = QuestState.Completed; if (!completedQuests.Contains(quest)) completedQuests.Add(quest); // Grant rewards GrantQuestRewards(quest); Debug.Log($"Quest Completed: {quest.questName}"); onQuestCompleted?.Invoke(quest); UpdateQuestUIFromCurrent(); return true; } /// /// Fail a quest by ID /// public bool FailQuest(string questId) { Quest quest = GetActiveQuest(questId); if (quest == null) { Debug.LogWarning($"Active quest '{questId}' not found."); return false; } return FailQuest(quest); } /// /// Fail a quest /// public bool FailQuest(Quest quest) { if (quest == null) { Debug.LogWarning("Cannot fail null quest."); return false; } if (!quest.IsActive()) { Debug.LogWarning($"Quest '{quest.questName}' is not active."); return false; } // Remove from active, add to failed activeQuests.Remove(quest); quest.state = QuestState.Failed; if (!failedQuests.Contains(quest)) failedQuests.Add(quest); Debug.Log($"Quest Failed: {quest.questName}"); onQuestFailed?.Invoke(quest); UpdateQuestUIFromCurrent(); return true; } /// /// Grant rewards to player (override/extend this for your reward system) /// protected virtual void GrantQuestRewards(Quest quest) { Debug.Log($"Granting rewards: {quest.experienceReward} XP, {quest.goldReward} Gold"); if (quest.itemRewards != null && quest.itemRewards.Length > 0) { Debug.Log($"Granting items: {string.Join(", ", quest.itemRewards)}"); } // TODO: Implement actual reward granting to player // e.g., Player.current.AddExperience(quest.experienceReward); // e.g., Player.current.AddGold(quest.goldReward); } /// /// Get quest by ID from available quests /// public Quest GetQuestById(string questId) { return availableQuests.FirstOrDefault(q => q.questId == questId); } /// /// Get active quest by ID /// public Quest GetActiveQuest(string questId) { return activeQuests.FirstOrDefault(q => q.questId == questId); } /// /// Check if quest is active /// public bool IsQuestActive(string questId) { return activeQuests.Any(q => q.questId == questId); } /// /// Check if quest is completed /// public bool IsQuestCompleted(string questId) { return completedQuests.Any(q => q.questId == questId); } /// /// Check if player can accept this quest /// public bool CanAcceptQuest(string questId) { Quest quest = GetQuestById(questId); if (quest == null || !quest.CanStart()) return false; // Check prerequisites if (!string.IsNullOrEmpty(quest.prerequisiteQuestId)) { if (!IsQuestCompleted(quest.prerequisiteQuestId)) return false; } return true; } /// /// Get all active quests /// public List GetActiveQuests() { return new List(activeQuests); } /// /// Get all completed quests /// public List GetCompletedQuests() { return new List(completedQuests); } /// /// Reset all quest progress (for testing or new game) /// public void ResetAllQuests() { foreach (Quest quest in availableQuests) { quest.Reset(); } activeQuests.Clear(); completedQuests.Clear(); failedQuests.Clear(); Debug.Log("All quests reset."); UpdateQuestUIFromCurrent(); } private void UpdateQuestUIFromCurrent() { Quest current = activeQuests.FirstOrDefault(); UpdateQuestUI(current); } private void UpdateQuestUI(Quest quest) { if (currentQuestTitleText == null && currentQuestDescriptionText == null) return; if (quest == null) { if (currentQuestTitleText != null) currentQuestTitleText.text = "No Active Quest"; if (currentQuestDescriptionText != null) currentQuestDescriptionText.text = string.Empty; return; } if (currentQuestTitleText != null) currentQuestTitleText.text = quest.questName; if (currentQuestDescriptionText != null) { currentQuestDescriptionText.text = $"Objective: {quest.questName}\nProgress: {quest.currentProgress}/{quest.requiredProgress}"; } } }