I wanted to introduce a notion of quantity for the objectives inside a quest.
Like “Kill 5 globins” or “Go fetch for me 7 flowers”
So I made a few change, but not much honestly, it was pretty easy to handle, because our QuestStatus already do the majority of the hard work.
Inside Quest.cs I modified the class Objective and added a method GetObjectiveQuantityRequired
public class Objective
{
public string reference;
public string description;
[Min(1)]
[SerializeField] int quantity = 1;
public int GetQuantity()
{
return quantity;
}
}
public int GetObjectiveQuantityRequired(string objectiveReference)
{
foreach (Objective objective in objectives)
{
if (objective.reference == objectiveReference)
{
return objective.GetQuantity();
}
}
// The objective was not found.
return -1;
}
And inside QuestStatus (the method CompleteObjective is the juicy part)
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace RPG.Quests
{
[System.Serializable]
public class QuestStatus
{
[SerializeField] private Quest quest;
[SerializeField] private List<string> completedObjectives = new List<string>();
private Dictionary<string, int> objectivesOnGoing = new Dictionary<string, int>();
[System.Serializable]
class QuestStatusRecord
{
public string questName;
public List<string> completedObjectives;
public Dictionary<string, int> objectivesOnGoing;
}
public QuestStatus(Quest quest)
{
this.quest = quest;
}
public QuestStatus(object objectState)
{
QuestStatusRecord state = objectState as QuestStatusRecord;
if (state == null) return;
this.quest = Quest.GetByName(state.questName);
this.completedObjectives = state.completedObjectives;
this.objectivesOnGoing = state.objectivesOnGoing;
}
public Quest GetQuest()
{
return quest;
}
public List<string> GetCompletedObjectives()
{
return completedObjectives;
}
public bool IsObjectiveComplete(string objective)
{
return completedObjectives.Contains(objective);
}
public void CompleteObjective(string objective)
{
if (quest.HasObjective(objective))
{
int objectiveQuantityDone = 1;
if (objectivesOnGoing.ContainsKey(objective))
{
objectiveQuantityDone += objectivesOnGoing[objective];
}
if (objectiveQuantityDone >= quest.GetObjectiveQuantityRequired(objective))
{
completedObjectives.Add(objective);
if (objectivesOnGoing.ContainsKey(objective))
{
objectivesOnGoing.Remove(objective);
}
}
else
{
objectivesOnGoing[objective] = objectiveQuantityDone;
}
}
}
public object CaptureState()
{
QuestStatusRecord record = new QuestStatusRecord();
record.questName = this.quest.GetTitle();
record.completedObjectives = this.completedObjectives;
record.objectivesOnGoing = this.objectivesOnGoing;
return record;
}
public bool IsComplete()
{
foreach (var objective in quest.GetObjectives())
{
if (!completedObjectives.Contains(objective.reference))
{
return false;
}
}
return true;
}
}
}
I have not yet modified the UI to handle the display of the quantity for objectives, but it should not be terribly difficult. I will update this post when it’s done.