using System.Collections.Generic; using UnityEngine; using UnityEngine.InputSystem; public enum ObjectiveType { Interact, Kill, Collect, None } [System.Serializable] public class QuestObjective { [Tooltip("Unique ID for this objective (e.g., 'bandit_leader', 'wolf_pelt')")] public string targetID; [Tooltip("What action the player must perform")] public ObjectiveType type; [Tooltip("The text shown in the UI")] public string description; [Header("Counting")] public bool requiresCount; public int currentCount; public int targetCount; [HideInInspector] public bool isCompleted; } [System.Serializable] public class Quest { public string questName; public List objectives = new List(); public bool isCompleted; } public class QuestManager : MonoBehaviour { public static QuestManager Instance { get; private set; } [Header("Current Quest")] public Quest activeQuest; [Header("Testing")] [Tooltip("Set the key to automatically progress the first incomplete objective")] public Key completeObjectiveKey = Key.O; // We notify the UI when the quest updates public delegate void OnQuestUpdated(); public event OnQuestUpdated onQuestUpdated; private void Awake() { if (Instance == null) { Instance = this; } else { Destroy(gameObject); } } private void Start() { // Tell UI to draw whatever quest is assigned in the inspector (if any) NotifyUI(); } private void Update() { if (Keyboard.current != null && Keyboard.current[completeObjectiveKey].wasPressedThisFrame) { // For testing: progress the first incomplete objective if (activeQuest != null && !activeQuest.isCompleted) { foreach (var obj in activeQuest.objectives) { if (!obj.isCompleted) { ProgressObjective(obj.type, obj.targetID, 1); break; } } } } } /// /// NPCs or Items can call this to progress the current quest! /// Example: QuestManager.Instance.ProgressObjective(ObjectiveType.Kill, "wolf"); /// public bool ProgressObjective(ObjectiveType type, string targetID, int amount = 1) { if (activeQuest == null || activeQuest.isCompleted) return false; foreach (var obj in activeQuest.objectives) { // Only progress the FIRST incomplete objective (Linear Quests) if (!obj.isCompleted) { // Check if this objective matches the action if (obj.type == type && obj.targetID == targetID) { if (obj.requiresCount) { obj.currentCount += amount; Debug.Log($"[QuestManager] Progressed '{obj.description}': {obj.currentCount}/{obj.targetCount}"); if (obj.currentCount >= obj.targetCount) { obj.currentCount = obj.targetCount; obj.isCompleted = true; Debug.Log($"[QuestManager] Objective Completed: {obj.description}"); } } else { obj.isCompleted = true; Debug.Log($"[QuestManager] Objective Completed: {obj.description}"); } CheckQuestCompletion(); NotifyUI(); return true; // Successfully progressed! } // If it didn't match, we still stop here because we only allow // progressing the CURRENT active objective. return false; } } return false; } /// /// Checks if a specific objective is the CURRENT active objective the player needs to do. /// public bool IsObjectiveActive(ObjectiveType type, string targetID) { if (activeQuest == null || activeQuest.isCompleted) return false; foreach (var obj in activeQuest.objectives) { if (!obj.isCompleted) { // We found the FIRST incomplete objective! Is it this one? return (obj.type == type && obj.targetID == targetID); } } return false; } private void CheckQuestCompletion() { foreach (var obj in activeQuest.objectives) { if (!obj.isCompleted) return; // Still have objectives left } activeQuest.isCompleted = true; Debug.Log($"[QuestManager] Quest Completed: {activeQuest.questName}"); } public void NotifyUI() { onQuestUpdated?.Invoke(); } /// /// An NPC or Item can call this to give the player a brand new quest! /// public void StartNewQuest(Quest newQuest) { activeQuest = newQuest; NotifyUI(); Debug.Log($"[QuestManager] Started new quest: {newQuest.questName}"); } }