Files
LowPolyRPG/Assets/Scripts/Quests/QuestManager.cs
Caleb Sandford deQuincey 715fb68744 Initial commitment
2025-06-25 11:10:11 +01:00

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");
}
}
}