Working on quests, moved to CineMachine for camera and started to build out areas, started combat system
This commit is contained in:
391
Assets/Scripts/Managers/QuestManager.cs
Normal file
391
Assets/Scripts/Managers/QuestManager.cs
Normal file
@@ -0,0 +1,391 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine.Events;
|
||||
using TMPro;
|
||||
|
||||
/// <summary>
|
||||
/// Centralized manager for all quests in the game
|
||||
/// Handles quest state transitions and tracking
|
||||
/// </summary>
|
||||
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<Quest> availableQuests = new List<Quest>();
|
||||
|
||||
[Header("Runtime Quest Tracking")]
|
||||
[SerializeField]
|
||||
private List<Quest> activeQuests = new List<Quest>();
|
||||
[SerializeField]
|
||||
private List<Quest> completedQuests = new List<Quest>();
|
||||
[SerializeField]
|
||||
private List<Quest> failedQuests = new List<Quest>();
|
||||
|
||||
[Header("Events")]
|
||||
public UnityEvent<Quest> onQuestStarted;
|
||||
public UnityEvent<Quest> onQuestProgressed;
|
||||
public UnityEvent<Quest> onQuestCompleted;
|
||||
public UnityEvent<Quest> 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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start a quest by ID
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start a quest
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Progress a quest by ID
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Progress a quest
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Complete a quest by ID
|
||||
/// </summary>
|
||||
public bool CompleteQuest(string questId)
|
||||
{
|
||||
Quest quest = GetActiveQuest(questId);
|
||||
if (quest == null)
|
||||
{
|
||||
Debug.LogWarning($"Active quest '{questId}' not found.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return CompleteQuest(quest);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Complete a quest and grant rewards
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fail a quest by ID
|
||||
/// </summary>
|
||||
public bool FailQuest(string questId)
|
||||
{
|
||||
Quest quest = GetActiveQuest(questId);
|
||||
if (quest == null)
|
||||
{
|
||||
Debug.LogWarning($"Active quest '{questId}' not found.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return FailQuest(quest);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fail a quest
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Grant rewards to player (override/extend this for your reward system)
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get quest by ID from available quests
|
||||
/// </summary>
|
||||
public Quest GetQuestById(string questId)
|
||||
{
|
||||
return availableQuests.FirstOrDefault(q => q.questId == questId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get active quest by ID
|
||||
/// </summary>
|
||||
public Quest GetActiveQuest(string questId)
|
||||
{
|
||||
return activeQuests.FirstOrDefault(q => q.questId == questId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if quest is active
|
||||
/// </summary>
|
||||
public bool IsQuestActive(string questId)
|
||||
{
|
||||
return activeQuests.Any(q => q.questId == questId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if quest is completed
|
||||
/// </summary>
|
||||
public bool IsQuestCompleted(string questId)
|
||||
{
|
||||
return completedQuests.Any(q => q.questId == questId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if player can accept this quest
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get all active quests
|
||||
/// </summary>
|
||||
public List<Quest> GetActiveQuests()
|
||||
{
|
||||
return new List<Quest>(activeQuests);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get all completed quests
|
||||
/// </summary>
|
||||
public List<Quest> GetCompletedQuests()
|
||||
{
|
||||
return new List<Quest>(completedQuests);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset all quest progress (for testing or new game)
|
||||
/// </summary>
|
||||
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}";
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user