Hey Brian, here is my code:
First my Questlist. It has the IPredicateEvaluator interface on it.
void Start()
{
achievementCounter.onCountChanged += CompleteObjectivesByPredicates;
}
public void AddQuest(Quest quest)
{
if (HasQuest(quest)) return;
QuestStatus newStatus = new QuestStatus(quest);
statuses.Add(newStatus);
GetComponent<Sounds>().PlayAudioClip(questRecievedSound);
foreach (Quest.Objective obj in quest.GetObjectives())
{
if (obj.GetPredicateConditionType() == PredicateType.HasKilled)
{
achievementCounter.RegisterCounter(obj.GetConditionParamater(0), true);
Int32.TryParse(obj.GetConditionParamater(1), out int maxAmount);
achievementCounter.RegisterMaxCounter(obj.GetConditionParamater(0),maxAmount, false);
}
}
OnQuestListEvent?.Invoke();
}
public void CompleteObjective(Quest quest, string objective)
{
var status = GetQuestStatus(quest);
if (status != null)
{
if (status.IsComplete())
{
Debug.Log("Status is complete");
}
status.CompleteObjective(objective);
OnQuestListEvent?.Invoke();
}
}
// Called by the UI when player hits complete quest to give player the quest reward
public bool CompleteQuest(Quest quest)
{
var status = GetQuestStatus(quest);
if (status != null)
{
if (status.IsComplete())
{
GiveReward(quest);
return true;
}
}
return false;
}
private void CompleteObjectivesByPredicates()
{
foreach (QuestStatus status in statuses)
{
if (status.IsComplete()) continue;
Quest quest = status.GetQuest();
foreach (var objective in quest.GetObjectives())
{
// Debug.Log($"Evaluating objective{objective.description}");
// Debug.Log($"Objective type: {objective.GetPredicateConditionType()}");
// Debug.Log($"Objective Paramater 0: {objective.GetConditionParamater(0)}");
// Debug.Log($"Objective Paramater 1: {objective.GetConditionParamater(1)}");
if (status.IsObjectiveComplete(objective.reference)) continue;
if (!objective.usesCondition) continue;
IPredicateEvaluator[] predArray = transform.GetComponents<IPredicateEvaluator>();
Debug.Log(predArray.Length); // this gives out an array length of 6, so its being captured
if (objective.completionCondition.Check(predArray))
{
// This line of code is never called it seems
Debug.Log("objective completed.");
CompleteObjective(quest, objective.reference);
}
}
}
}
Here is the counter class as you provided , it should be identical. It also has the IPredicateEvaluator on it just like the quest list.
I didn’t post ALL the script because you already have it but this is the evaluator we used.
public bool? Evaluate(PredicateType predicate, string[] parameters)
{
if (predicate == PredicateType.HasKilled)
{
if (int.TryParse(parameters[1], out int intParameter))
{
RegisterCounter(parameters[0]);
Debug.Log(counts[parameters[0]] >= intParameter);
return counts[parameters[0]] >= intParameter;
}
return false;
}
return false;
}
Both the quest list and achievement counter sit on the player object.
Just for completion sake, here is my condition script and predicate class.
[System.Serializable]
public class Condition
{
[SerializeField]
Disjunction[] and;
public PredicateType GetConditionType()
{
return and[0].GetPredicate().GetPredicateType();
}
public string GetPredicateParamater(int index)
{
return and[0].GetPredicate().GetParamaters(index);
}
public bool Check(IEnumerable<IPredicateEvaluator> evaluators)
{
foreach (Disjunction dis in and)
{
if (!dis.Check(evaluators))
{
return false;
}
}
return true;
}
[System.Serializable]
class Disjunction
{
[SerializeField]
Predicate[] or;
public Predicate GetPredicate()
{
return or[0];
}
public bool Check(IEnumerable<IPredicateEvaluator> evaluators)
{
foreach (Predicate p in or)
{
if (p.Check(evaluators))
{
return true;
}
}
return false;
}
}
[System.Serializable]
public class Predicate
{
[SerializeField] PredicateType predicate;
[SerializeField] bool negate = false;
[SerializeField] string[] parameters;
public PredicateType GetPredicateType()
{
return predicate;
}
public string GetParamaters(int index)
{
return parameters[index];
}
public bool Check(IEnumerable<IPredicateEvaluator> evaluators)
{
foreach (var evaluator in evaluators)
{
bool? result = evaluator.Evaluate(predicate, parameters);
if (result == null)
{
continue;
}
if (result == negate) return false;
}
return true;
}
}
}
Predicate enum and class.
public enum PredicateType
{
Select, // placeholder, reminds you to select a predicate
HasQuest,
HasCompletedObjective,
HasCompletedQuest,
HasLevel,
MinimumTrait,
HasItem,
HasItems,
HasItemEquipped,
HasKilled
}
public interface IPredicateEvaluator
{
bool? Evaluate(PredicateType predicate, string[] paramters);
}
Hopefully this helps figure it out. I’m just stuck. Quest list is getting the predicate evlauator call when the counter updates because of myu debug logs but it never gets passed the Check bool function. Furthermore, the achievementcounter evaluator is not being called because my debug.log in that function is never called so I know its not being called which I can’t figure out why. I left some comments in that function to give you a sense of where it breaksdown.