Amending Quest System to include Objectives

This commit is contained in:
SHOUTING_PIRATE
2025-05-07 17:41:41 +01:00
parent 4e0bc0a573
commit 722baa9a2f
65 changed files with 10720 additions and 9633 deletions

Binary file not shown.

View File

@@ -0,0 +1,23 @@
{
"Version": 1,
"WorkspaceRootPath": "E:\\Unity\\Projects\\CartoonRPG\\Assets\\Scripts\\",
"Documents": [],
"DocumentGroupContainers": [
{
"Orientation": 0,
"VerticalTabListWidth": 256,
"DocumentGroups": [
{
"DockedWidth": 200,
"SelectedChildIndex": -1,
"Children": [
{
"$type": "Bookmark",
"Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}"
}
]
}
]
}
]
}

View File

@@ -0,0 +1,6 @@
{
"ExpandedNodes": [
""
],
"PreviewInSolutionExplorer": false
}

Binary file not shown.

View File

@@ -5,16 +5,30 @@ public class Quest : MonoBehaviour
public string questName;
public string description;
public bool isCompleted;
public bool isStarted;
public bool isFailed;
public bool isAbandoned;
public void StartQuest()
{
if(isStarted || isCompleted || isFailed || isAbandoned)
{
Debug.LogWarning($"Quest '{questName}' is already in a state that prevents starting.");
return;
}
isCompleted = false;
isStarted = true;
// Add quest start logic here
Debug.Log($"Quest '{questName}' has started!");
}
public void CompleteQuest()
{
if(isCompleted || isFailed || isAbandoned)
{
Debug.LogWarning($"Quest '{questName}' is already in a state that prevents completion.");
return;
}
isCompleted = true;
// Add quest completion logic here
Debug.Log($"Quest '{questName}' has been completed!");
@@ -24,4 +38,35 @@ public class Quest : MonoBehaviour
{
return isCompleted;
}
public void ProgressQuest()
{
// Add quest progress logic here
Debug.Log($"Quest '{questName}' has been progressed!");
}
public void FailQuest()
{
if(isFailed || isAbandoned)
{
Debug.LogWarning($"Quest '{questName}' is already in a state that prevents failure.");
return;
}
isFailed = true;
// Add quest failure logic here
Debug.Log($"Quest '{questName}' has failed!");
}
public void AbandonQuest()
{
if(isAbandoned)
{
Debug.LogWarning($"Quest '{questName}' is already in a state that prevents abandonment.");
return;
}
isAbandoned = true;
// Add quest abandonment logic here
Debug.Log($"Quest '{questName}' has been abandoned!");
}
}

View File

@@ -2,10 +2,44 @@ using UnityEngine;
using System.Collections.Generic;
using System.Collections;
public enum ObjectiveType
{
Collect,
Kill,
TalkTo,
Deliver,
Explore,
Reach
}
[System.Serializable]
public class Objective
{
public int id;
public string description;
public ObjectiveType type;
public int targetAmount;
public string targetItem;
public bool isOptional; // Optional objectives don't block quest completion
}
[System.Serializable]
public class Quest
{
public int id;
public string name;
public string description;
public int experienceReward;
public int goldReward;
public bool isRepeatable;
public List<int> requiredQuests;
public List<Objective> objectives;
}
[CreateAssetMenu(fileName = "QuestDatabase", menuName = "Quest/Quest Database", order = 0)]
public class QuestAssets : ScriptableObject
{
[SerializeField] private List<QuestEntry> entries = new List<QuestEntry>();
[SerializeField] private List<Quest> quests = new List<Quest>();
public List<QuestEntry> Entries => entries;
public List<Quest> Quests => quests;
}

View File

@@ -4,29 +4,32 @@ using System.Collections;
using System;
using TMPro;
[System.Serializable]
public class QuestEntry
namespace CartoonRPG.Quests
{
public int questId; // Changed from string to int
public string questName;
public string questDescription;
public List<QuestData> quests;
}
// Removed redundant using directive
[System.Serializable]
public class QuestData
public class Quest
{
public int id;
public string name;
public string description;
public QuestType type;
public int targetAmount;
public string targetItem;
public int experienceReward;
public int goldReward;
public bool isRepeatable;
public List<int> requiredQuests; // Quest IDs that must be completed first
}
public List<Objective> objectives;
[System.Serializable]
public class Objective
{
public int id;
public string description;
public ObjectiveType type;
public int targetAmount;
public string targetItem;
public bool isOptional; // Optional objectives don't block quest completion
} // Closing brace for Quest class
public enum QuestType
{
@@ -44,7 +47,7 @@ public class QuestDatabase : MonoBehaviour
[SerializeField] private QuestAssets questAssets;
[SerializeField] private TMPro.TMP_Text questNameText;
[SerializeField] private TMPro.TMP_Text questObjectiveText;
private Dictionary<int, QuestEntry> questDictionary;
private Dictionary<int, Quest> questDictionary;
private static QuestDatabase instance;
public static QuestDatabase Instance
@@ -58,6 +61,7 @@ public class QuestDatabase : MonoBehaviour
{
GameObject obj = new GameObject("QuestDatabase");
instance = obj.AddComponent<QuestDatabase>();
}
}
}
return instance;
@@ -80,48 +84,48 @@ public class QuestDatabase : MonoBehaviour
private void InitializeDictionary()
{
questDictionary = new Dictionary<int, QuestEntry>();
questDictionary = new Dictionary<int, Quest>();
if (questAssets != null)
{
foreach (var entry in questAssets.Entries)
foreach (var quest in questAssets.Quests)
{
questDictionary.Add(entry.questId, entry);
}
if (quest != null)
{
questDictionary.Add(quest.id, (CartoonRPG.Quests.Quest)quest);
}
else
{
Debug.LogError("Invalid quest found in questAssets.Quests.");
}
}
}
}
public QuestData GetQuest(int questId)
public Quest GetQuest(int questId)
{
if (questDictionary.TryGetValue(questId, out var entry))
{
return entry.quests.Find(q => q.id == questId);
}
return null;
return questDictionary.TryGetValue(questId, out var quest) ? quest : null;
}
public List<QuestData> GetAvailableQuests(int npcId)
public List<Quest> GetAvailableQuests(int npcId)
{
List<QuestData> availableQuests = new List<QuestData>();
List<Quest> availableQuests = new List<Quest>();
foreach (var entry in questDictionary.Values)
foreach (var quest in questDictionary.Values)
{
foreach (var quest in entry.quests)
// Check prerequisites
bool prerequisitesMet = true;
foreach (int requiredQuest in quest.requiredQuests)
{
// Check prerequisites
bool prerequisitesMet = true;
foreach (int requiredQuest in quest.requiredQuests)
if (!IsQuestCompleted(requiredQuest))
{
if (!IsQuestCompleted(requiredQuest))
{
prerequisitesMet = false;
break;
}
prerequisitesMet = false;
break;
}
}
if (prerequisitesMet)
{
availableQuests.Add(quest);
}
if (prerequisitesMet)
{
availableQuests.Add(quest);
}
}
@@ -135,25 +139,81 @@ public class QuestDatabase : MonoBehaviour
return availableQuests;
}
private Dictionary<int, int> questProgress = new Dictionary<int, int>();
private Dictionary<int, Dictionary<int, int>> objectiveProgress = new Dictionary<int, Dictionary<int, int>>();
private Dictionary<int, Dictionary<int, bool>> completedObjectives = new Dictionary<int, Dictionary<int, bool>>();
private Dictionary<int, bool> completedQuests = new Dictionary<int, bool>();
public void UpdateQuestProgress(int questId, int amount = 1)
public void UpdateObjectiveProgress(int questId, int objectiveId, int amount = 1)
{
if (questProgress.ContainsKey(questId))
if (objectiveProgress.ContainsKey(questId))
{
questProgress[questId] += amount;
if (objectiveProgress[questId].ContainsKey(objectiveId))
{
objectiveProgress[questId][objectiveId] += amount;
}
else
{
objectiveProgress[questId][objectiveId] = amount;
}
}
else
{
questProgress[questId] = amount;
objectiveProgress[questId] = new Dictionary<int, int> { { objectiveId, amount } };
}
// Check if quest is completed
QuestData quest = GetQuest(questId);
if (quest != null && questProgress[questId] >= quest.targetAmount)
// Check if objective is completed
Quest quest = GetQuest(questId);
if (quest != null)
{
CompleteQuest(questId);
var objective = quest.objectives.Find(o => o.id == objectiveId);
if (objective != null && objectiveProgress[questId][objectiveId] >= objective.targetAmount)
{
CompleteObjective(questId, objectiveId);
}
}
public void CompleteObjective(int questId, int objectiveId)
{
if (completedObjectives.ContainsKey(questId))
{
if (completedObjectives[questId].ContainsKey(objectiveId))
{
if (completedObjectives[questId][objectiveId])
{
return;
}
}
else
{
completedObjectives[questId][objectiveId] = true;
}
}
else
{
completedObjectives[questId] = new Dictionary<int, bool> { { objectiveId, true } };
}
// Check if all required objectives are completed
Quest quest = GetQuest(questId);
if (quest != null)
{
bool allRequiredObjectivesCompleted = true;
foreach (var objective in quest.objectives)
{
if (!objective.isOptional &&
(!completedObjectives.ContainsKey(questId) ||
!completedObjectives[questId].ContainsKey(objective.id) ||
!completedObjectives[questId][objective.id]))
{
allRequiredObjectivesCompleted = false;
break;
}
}
if (allRequiredObjectivesCompleted)
{
CompleteQuest(questId);
}
}
}
@@ -168,7 +228,7 @@ public class QuestDatabase : MonoBehaviour
}
completedQuests[questId] = true;
QuestData quest = GetQuest(questId);
Quest quest = GetQuest(questId);
if (quest != null)
{
// Grant rewards
@@ -188,29 +248,40 @@ public class QuestDatabase : MonoBehaviour
}
// Check for any quests that require this quest as a prerequisite
foreach (var q in questDictionary.Values)
{
if (q.requiredQuests.Contains(questId))
{
// TODO: Make these quests available
}
}
} // Check for any quests that require this quest as a prerequisite
foreach (var entry in questDictionary.Values)
{
foreach (var q in entry.quests)
if (entry.requiredQuests.Contains(questId))
{
if (q.requiredQuests.Contains(questId))
{
// TODO: Make these quests available
// TODO: Make these quests available
}
}
}
}
// Check for any quests that require this quest as a prerequisite
foreach (var entry in questDictionary.Values)
{
foreach (var q in entry.quests)
{
if (q.requiredQuests.Contains(questId))
{
// TODO: Make these quests available
}
}
}
public bool IsObjectiveCompleted(int questId, int objectiveId)
{
if (completedObjectives.ContainsKey(questId) && completedObjectives[questId].ContainsKey(objectiveId))
{
return completedObjectives[questId][objectiveId];
}
return false;
}
public int GetObjectiveProgress(int questId, int objectiveId)
{
if (objectiveProgress.ContainsKey(questId) && objectiveProgress[questId].ContainsKey(objectiveId))
{
return objectiveProgress[questId][objectiveId];
}
return 0;
}
public bool IsQuestCompleted(int questId)
@@ -218,14 +289,26 @@ public class QuestDatabase : MonoBehaviour
return completedQuests.ContainsKey(questId) && completedQuests[questId];
}
public int GetQuestProgress(int questId)
{
return questProgress.ContainsKey(questId) ? questProgress[questId] : 0;
}
public void ResetQuestProgress(int questId)
{
questProgress[questId] = 0;
if (objectiveProgress.ContainsKey(questId))
{
objectiveProgress[questId].Clear();
}
else
{
objectiveProgress[questId] = new Dictionary<int, int>();
}
if (completedObjectives.ContainsKey(questId))
{
completedObjectives[questId].Clear();
}
else
{
completedObjectives[questId] = new Dictionary<int, bool>();
}
completedQuests[questId] = false;
// Reset UI visibility
@@ -251,7 +334,7 @@ public class QuestDatabase : MonoBehaviour
}
completedQuests[questId] = true;
QuestData quest = GetQuest(questId);
Quest quest = GetQuest(questId);
if (quest != null)
{
// Update UI
@@ -280,7 +363,7 @@ public class QuestDatabase : MonoBehaviour
}
completedQuests[questId] = true;
QuestData quest = GetQuest(questId);
Quest quest = GetQuest(questId);
if (quest != null)
{
// Update UI
@@ -298,7 +381,7 @@ public class QuestDatabase : MonoBehaviour
}
}
public void UpdateQuestUI(QuestData quest)
public void UpdateQuestUI(Quest quest)
{
if (quest == null)
{
@@ -314,8 +397,13 @@ public class QuestDatabase : MonoBehaviour
if (questObjectiveText != null)
{
int progress = GetQuestProgress(quest.id);
string objectiveText = $"{quest.description}";
// Show progress for all objectives
string objectiveText = "";
foreach (var objective in quest.objectives)
{
int progress = GetObjectiveProgress(quest.id, objective.id);
objectiveText += $"\n{progress}/{objective.targetAmount} {objective.description}";
}
questObjectiveText.text = objectiveText;
questObjectiveText.gameObject.SetActive(true);
}