Sure, here you go (and for the post regarding my infinity glitch, there’s no way I can respond there regarding the fix of the infinity reward glitch):
using System;
using System.Collections.Generic;
using UnityEngine;
using GameDevTV.Saving;
using GameDevTV.Inventories;
using GameDevTV.Utils;
using Newtonsoft.Json.Linq;
namespace RPG.Quests {
public class QuestList : MonoBehaviour, IPredicateEvaluator, IJsonSaveable //, ISaveable
{
List<QuestStatus> statuses = new List<QuestStatus>(); // for Restoring State, our object state is this list, which is [System.Serializable]
public event Action onUpdate;
private void Update() {
CompleteObjectivesByPredicates();
}
public void AddQuest(Quest quest) {
if (HasQuest(quest)) return;
QuestStatus newStatus = new QuestStatus(quest);
statuses.Add(newStatus);
// This line below is responsible for my quest dialogue not closing properly at the end of the conversation:
/* if (onUpdate != null) {
onUpdate();
} */
}
public bool HasQuest(Quest quest)
{
return GetQuestStatus(quest) != null;
}
public IEnumerable<QuestStatus> GetStatuses()
{
return statuses;
}
public void CompleteObjective(Quest quest, string objective)
{
QuestStatus status = GetQuestStatus(quest);
status.CompleteObjective(objective);
if (status.IsComplete()) {
GiveReward(quest);
}
// This function below is responsible for my infinity reward glitch, so I commented it out:
/* if (OnUpdate != null) {
OnUpdate();
} */
}
/* public object CaptureState() {
List<object> state = new List<object>();
foreach (QuestStatus status in statuses) {
state.Add(status.CaptureState());
}
return state;
}
public void RestoreState(object state) {
List<object> stateList = state as List<object>;
if (stateList == null) return;
statuses.Clear();
foreach (object objectState in stateList) {
statuses.Add(new QuestStatus(objectState));
}
} */
public JToken CaptureAsJToken() {
JArray state = new JArray();
IList<JToken> stateList = state;
foreach (QuestStatus status in statuses) {
stateList.Add(status.CaptureAsJToken());
}
return state;
}
public void RestoreFromJToken(JToken state) {
if (state is JArray stateArray) {
statuses.Clear();
IList<JToken> stateList = stateArray;
foreach (JToken token in stateList) {
statuses.Add(new QuestStatus(token));
}
}
}
private QuestStatus GetQuestStatus(Quest quest)
{
foreach (QuestStatus status in statuses)
{
if (status.GetQuest() == quest)
{
return status;
}
}
return null;
}
private void GiveReward(Quest quest)
{
foreach (var reward in quest.GetRewards()) {
bool success = GetComponent<Inventory>().AddToFirstEmptySlot(reward.item, reward.number);
if (!success) {
GetComponent<ItemDropper>().DropItem(reward.item, reward.number); // if our player didn't have enough inventory slots to take their reward, drop the rewards on the ground
}
}
}
/* public bool? Evaluate(string predicate, string[] parameters)
{
switch(predicate) {
case "HasQuest": return HasQuest(Quest.GetByName(parameters[0]));
case "CompletedQuest": return GetQuestStatus(Quest.GetByName(parameters[0])).IsComplete();
}
return null;
} */
public bool? Evaluate(EPredicate predicate, string[] parameters) {
// New function to go with the Enum Predicate we developed in 'IPredicateEvaluator.cs' (Replacing the string-based 'Evaluate' function above)
switch (predicate) {
// Quest is given to player:
case EPredicate.HasQuest: return HasQuest(Quest.GetByName(parameters[0]));
// Quest Completed:
case EPredicate.CompletedQuest:
QuestStatus status = GetQuestStatus(Quest.GetByName(parameters[0]));
if (status == null) return false;
return status.IsComplete();
// Completed Objective:
case EPredicate.CompletedObjective:
QuestStatus testStatus = GetQuestStatus(Quest.GetByName(parameters[0]));
if (testStatus == null) return false;
return testStatus.IsObjectiveComplete(parameters[1]);
}
// If no condition is met above, return null
return null;
}
public void CompleteObjectivesByPredicates()
{
// (Re-summarize this function - Shops and Abilities course, Lecture 94/96):
// This function enables Predicates in quests
// (so if we don't have a skill level accomplished yet for example, we can't work on the quest)
// (IT OPENS A TON OF POSSIBILITIES FOR QUESTS AS A RESULT!)
foreach (QuestStatus status in statuses) {
if (status.IsComplete()) continue;
Quest quest = status.GetQuest();
foreach (Quest.Objective objective in quest.GetObjectives()) {
if (status.IsObjectiveComplete(objective.reference)) { continue; }
if (!objective.usesCondition) continue;
if (objective.completionCondition.Check(GetComponents<IPredicateEvaluator>())) {
CompleteObjective(quest, objective.reference);
}
}
}
}
}
}
QuestListUI.cs:
using RPG.Quests;
using UnityEngine;
public class QuestListUI : MonoBehaviour
{
[SerializeField] QuestItemUI questPrefab;
QuestList questList;
// Start is called before the first frame update
void Start()
{
questList = GameObject.FindGameObjectWithTag("Player").GetComponent<QuestList>();
questList.onUpdate += Redraw;
Redraw();
}
private void Redraw()
{
foreach (Transform item in transform)
{
// avoids Dangling Nodes in the Hierarchy, which will eventually slow our entire game down
Destroy(item.gameObject);
}
foreach (QuestStatus status in questList.GetStatuses())
{
QuestItemUI UIInstance = Instantiate<QuestItemUI>(questPrefab, transform);
UIInstance.Setup(status);
}
}
}