442 lines
13 KiB
C#
442 lines
13 KiB
C#
using UnityEngine;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
public class QuestManager : MonoBehaviour
|
|
{
|
|
public static QuestManager Instance { get; private set; }
|
|
|
|
[Header("Quest Management")]
|
|
[SerializeField] private List<Quest> availableQuests = new List<Quest>();
|
|
[SerializeField] private List<Quest> activeQuests = new List<Quest>();
|
|
[SerializeField] private List<Quest> completedQuests = new List<Quest>();
|
|
[SerializeField] private List<Quest> failedQuests = new List<Quest>();
|
|
[SerializeField] private List<Quest> abandonedQuests = new List<Quest>();
|
|
|
|
[Header("Settings")]
|
|
[SerializeField] private int maxActiveQuests = 10;
|
|
[SerializeField] private bool debugMode = true;
|
|
|
|
// Events
|
|
public System.Action<Quest> OnQuestStarted;
|
|
public System.Action<Quest> OnQuestCompleted;
|
|
public System.Action<Quest> OnQuestFailed;
|
|
public System.Action<Quest> OnQuestAbandoned;
|
|
public System.Action<Quest, QuestObjective> OnObjectiveCompleted;
|
|
public System.Action<Quest, QuestObjective> OnObjectiveProgressed;
|
|
|
|
private void Awake()
|
|
{
|
|
Instance = this;
|
|
}
|
|
|
|
#region Quest Management
|
|
|
|
/// <summary>
|
|
/// Start a new quest
|
|
/// </summary>
|
|
public bool StartQuest(string questId)
|
|
{
|
|
var quest = GetQuestById(questId);
|
|
return StartQuest(quest);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Start a new quest
|
|
/// </summary>
|
|
public bool StartQuest(Quest quest)
|
|
{
|
|
if (quest == null)
|
|
{
|
|
LogError("Cannot start quest: Quest is null");
|
|
return false;
|
|
}
|
|
|
|
if (quest.status != QuestStatus.NotStarted && !quest.isRepeatable)
|
|
{
|
|
LogError($"Cannot start quest '{quest.questName}': Already started or not repeatable");
|
|
return false;
|
|
}
|
|
|
|
if (activeQuests.Count >= maxActiveQuests)
|
|
{
|
|
LogError($"Cannot start quest '{quest.questName}': Maximum active quests reached ({maxActiveQuests})");
|
|
return false;
|
|
}
|
|
|
|
if (!ArePrerequisitesMet(quest))
|
|
{
|
|
LogError($"Cannot start quest '{quest.questName}': Prerequisites not met");
|
|
return false;
|
|
}
|
|
|
|
// Reset quest if repeatable
|
|
if (quest.isRepeatable)
|
|
{
|
|
quest.ResetObjectives();
|
|
} quest.status = QuestStatus.Active;
|
|
activeQuests.Add(quest);
|
|
|
|
Log($"Quest started: {quest.questName}");
|
|
OnQuestStarted?.Invoke(quest);
|
|
|
|
// Update UI to show the new quest
|
|
UpdateQuest(quest);
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Complete a quest
|
|
/// </summary>
|
|
public bool CompleteQuest(string questId)
|
|
{
|
|
var quest = GetActiveQuest(questId);
|
|
return CompleteQuest(quest);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Complete a quest
|
|
/// </summary>
|
|
public bool CompleteQuest(Quest quest)
|
|
{
|
|
if (quest == null || quest.status != QuestStatus.Active)
|
|
{
|
|
LogError("Cannot complete quest: Quest not found or not active");
|
|
return false;
|
|
}
|
|
|
|
if (!quest.AreRequiredObjectivesCompleted())
|
|
{
|
|
LogError($"Cannot complete quest '{quest.questName}': Required objectives not completed");
|
|
return false;
|
|
}
|
|
|
|
quest.status = QuestStatus.Completed;
|
|
activeQuests.Remove(quest);
|
|
completedQuests.Add(quest);
|
|
|
|
// Give rewards
|
|
GiveQuestRewards(quest);
|
|
|
|
Log($"Quest completed: {quest.questName}");
|
|
OnQuestCompleted?.Invoke(quest);
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fail a quest
|
|
/// </summary>
|
|
public bool FailQuest(string questId)
|
|
{
|
|
var quest = GetActiveQuest(questId);
|
|
return FailQuest(quest);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fail a quest
|
|
/// </summary>
|
|
public bool FailQuest(Quest quest)
|
|
{
|
|
if (quest == null || quest.status != QuestStatus.Active)
|
|
{
|
|
LogError("Cannot fail quest: Quest not found or not active");
|
|
return false;
|
|
}
|
|
|
|
quest.status = QuestStatus.Failed;
|
|
activeQuests.Remove(quest);
|
|
failedQuests.Add(quest);
|
|
|
|
Log($"Quest failed: {quest.questName}");
|
|
OnQuestFailed?.Invoke(quest);
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Abandon a quest
|
|
/// </summary>
|
|
public bool AbandonQuest(string questId)
|
|
{
|
|
var quest = GetActiveQuest(questId);
|
|
return AbandonQuest(quest);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Abandon a quest
|
|
/// </summary>
|
|
public bool AbandonQuest(Quest quest)
|
|
{
|
|
if (quest == null || quest.status != QuestStatus.Active)
|
|
{
|
|
LogError("Cannot abandon quest: Quest not found or not active");
|
|
return false;
|
|
}
|
|
|
|
if (quest.isMainQuest)
|
|
{
|
|
LogError($"Cannot abandon quest '{quest.questName}': Main quests cannot be abandoned");
|
|
return false;
|
|
}
|
|
|
|
quest.status = QuestStatus.Abandoned;
|
|
activeQuests.Remove(quest);
|
|
abandonedQuests.Add(quest);
|
|
|
|
Log($"Quest abandoned: {quest.questName}");
|
|
OnQuestAbandoned?.Invoke(quest);
|
|
|
|
return true;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Objective Management /// <summary>
|
|
/// Progress a quest objective
|
|
/// </summary>
|
|
public bool ProgressObjective(string questId, string objectiveId, int amount = 1)
|
|
{
|
|
var quest = GetActiveQuest(questId);
|
|
if (quest == null) return false;
|
|
|
|
var objective = quest.GetObjective(objectiveId);
|
|
if (objective == null || objective.isCompleted) return false;
|
|
|
|
int previousAmount = objective.currentAmount;
|
|
objective.AddProgress(amount);
|
|
|
|
Log($"Objective progressed: {quest.questName} - {objective.description} ({objective.currentAmount}/{objective.targetAmount})");
|
|
OnObjectiveProgressed?.Invoke(quest, objective);
|
|
|
|
// Update UI to reflect objective progress
|
|
UpdateQuest(quest);
|
|
|
|
// Check if objective just completed
|
|
if (objective.isCompleted && previousAmount < objective.targetAmount)
|
|
{
|
|
Log($"Objective completed: {quest.questName} - {objective.description}");
|
|
OnObjectiveCompleted?.Invoke(quest, objective);
|
|
|
|
// Auto-complete quest if all required objectives are done
|
|
if (quest.AreRequiredObjectivesCompleted())
|
|
{
|
|
CompleteQuest(quest);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
} /// <summary>
|
|
/// Set objective progress to specific value
|
|
/// </summary>
|
|
public bool SetObjectiveProgress(string questId, string objectiveId, int amount)
|
|
{
|
|
var quest = GetActiveQuest(questId);
|
|
if (quest == null) return false;
|
|
|
|
var objective = quest.GetObjective(objectiveId);
|
|
if (objective == null) return false;
|
|
|
|
bool wasCompleted = objective.isCompleted;
|
|
objective.SetProgress(amount);
|
|
|
|
Log($"Objective progress set: {quest.questName} - {objective.description} ({objective.currentAmount}/{objective.targetAmount})");
|
|
OnObjectiveProgressed?.Invoke(quest, objective);
|
|
|
|
// Update UI to reflect objective progress
|
|
UpdateQuest(quest);
|
|
|
|
// Check if objective just completed
|
|
if (objective.isCompleted && !wasCompleted)
|
|
{
|
|
Log($"Objective completed: {quest.questName} - {objective.description}");
|
|
OnObjectiveCompleted?.Invoke(quest, objective);
|
|
|
|
// Auto-complete quest if all required objectives are done
|
|
if (quest.AreRequiredObjectivesCompleted())
|
|
{
|
|
CompleteQuest(quest);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Status Checking
|
|
|
|
/// <summary>
|
|
/// Get quest status
|
|
/// </summary>
|
|
public QuestStatus GetQuestStatus(string questId)
|
|
{
|
|
var quest = GetQuestById(questId);
|
|
return quest?.status ?? QuestStatus.NotStarted;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check if quest is active
|
|
/// </summary>
|
|
public bool IsQuestActive(string questId)
|
|
{
|
|
return GetQuestStatus(questId) == QuestStatus.Active;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check if quest is completed
|
|
/// </summary>
|
|
public bool IsQuestCompleted(string questId)
|
|
{
|
|
return GetQuestStatus(questId) == QuestStatus.Completed;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check if objective is completed
|
|
/// </summary>
|
|
public bool IsObjectiveCompleted(string questId, string objectiveId)
|
|
{
|
|
var quest = GetQuestById(questId);
|
|
var objective = quest?.GetObjective(objectiveId);
|
|
return objective?.isCompleted ?? false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get objective progress
|
|
/// </summary>
|
|
public int GetObjectiveProgress(string questId, string objectiveId)
|
|
{
|
|
var quest = GetQuestById(questId);
|
|
var objective = quest?.GetObjective(objectiveId);
|
|
return objective?.currentAmount ?? 0;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Helper Methods
|
|
|
|
private Quest GetQuestById(string questId)
|
|
{
|
|
return availableQuests.FirstOrDefault(q => q.questId == questId) ??
|
|
activeQuests.FirstOrDefault(q => q.questId == questId) ??
|
|
completedQuests.FirstOrDefault(q => q.questId == questId) ??
|
|
failedQuests.FirstOrDefault(q => q.questId == questId) ??
|
|
abandonedQuests.FirstOrDefault(q => q.questId == questId);
|
|
}
|
|
|
|
private Quest GetActiveQuest(string questId)
|
|
{
|
|
return activeQuests.FirstOrDefault(q => q.questId == questId);
|
|
}
|
|
|
|
private bool ArePrerequisitesMet(Quest quest)
|
|
{
|
|
if (quest.prerequisites == null || quest.prerequisites.Length == 0)
|
|
return true;
|
|
|
|
return quest.prerequisites.All(prereq => IsQuestCompleted(prereq.questId));
|
|
}
|
|
|
|
private void GiveQuestRewards(Quest quest)
|
|
{
|
|
// TODO: Implement reward system
|
|
// This would integrate with your inventory, experience, and currency systems
|
|
Log($"Rewards given for quest '{quest.questName}': {quest.experienceReward} XP, {quest.goldReward} Gold");
|
|
}
|
|
|
|
private void Log(string message)
|
|
{
|
|
if (debugMode)
|
|
Debug.Log($"[QuestManager] {message}");
|
|
}
|
|
|
|
private void LogError(string message)
|
|
{
|
|
Debug.LogError($"[QuestManager] {message}");
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Public Getters
|
|
|
|
public List<Quest> GetActiveQuests() => new List<Quest>(activeQuests);
|
|
public List<Quest> GetCompletedQuests() => new List<Quest>(completedQuests);
|
|
public List<Quest> GetFailedQuests() => new List<Quest>(failedQuests);
|
|
public List<Quest> GetAbandonedQuests() => new List<Quest>(abandonedQuests);
|
|
public List<Quest> GetAvailableQuests() => new List<Quest>(availableQuests);
|
|
|
|
#endregion
|
|
public void UpdateQuest(Quest quest)
|
|
{
|
|
if (quest == null) return;
|
|
|
|
// Update the quest in the available list
|
|
var existingQuest = GetQuestById(quest.questId);
|
|
if (existingQuest != null)
|
|
{
|
|
existingQuest = quest; // Replace with updated quest
|
|
Log($"Quest updated: {quest.questName}");
|
|
|
|
// Get current quest name and active objective
|
|
string currentQuestName = quest.questName;
|
|
string currentObjectiveText = "No active objectives";
|
|
|
|
// Get the current active objective
|
|
quest.GetCurrentObjective(out QuestObjective currentObjective, out int currentIndex);
|
|
if (currentObjective != null)
|
|
{
|
|
currentObjectiveText = $"{currentObjective.objectiveId} ({currentObjective.currentAmount}/{currentObjective.targetAmount})";
|
|
}
|
|
|
|
// Update the UI
|
|
if (UIController.Instance != null)
|
|
{
|
|
UIController.Instance.UpdateQuestUI(currentQuestName, currentObjectiveText);
|
|
}
|
|
else
|
|
{
|
|
LogError("UIController instance not found - cannot update quest UI");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LogError($"Cannot update quest: Quest '{quest.questName}' not found");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Update UI for the first active quest (primary quest display)
|
|
/// </summary>
|
|
public void UpdateActiveQuestUI()
|
|
{
|
|
if (activeQuests.Count > 0)
|
|
{
|
|
UpdateQuest(activeQuests[0]); // Update UI for the first active quest
|
|
}
|
|
else
|
|
{
|
|
// No active quests, clear the UI
|
|
if (UIController.Instance != null)
|
|
{
|
|
UIController.Instance.UpdateQuestUI("No Active Quests", "");
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Update UI for a specific quest by ID
|
|
/// </summary>
|
|
public void UpdateQuestUIById(string questId)
|
|
{
|
|
var quest = GetQuestById(questId);
|
|
if (quest != null && quest.status == QuestStatus.Active)
|
|
{
|
|
UpdateQuest(quest);
|
|
}
|
|
else
|
|
{
|
|
LogError($"Cannot update UI: Quest '{questId}' not found or not active");
|
|
}
|
|
}
|
|
} |