// Copyright (c) Pixel Crushers. All rights reserved.
using UnityEngine;
using System.Collections.Generic;
namespace PixelCrushers.DialogueSystem
{
public delegate QuestState StringToQuestStateDelegate(string s);
public delegate string QuestStateToStringDelegate(QuestState state);
public delegate string CurrentQuestStateDelegate(string quest);
public delegate void SetQuestStateDelegate(string quest, string state);
public delegate void SetQuestEntryStateDelegate(string quest, int entryNumber, string state);
public delegate string CurrentQuestEntryStateDelegate(string quest, int entryNumber);
public struct QuestEntryArgs
{
public string questName;
public int entryNumber;
public QuestEntryArgs(string questName, int entryNumber)
{
this.questName = questName;
this.entryNumber = entryNumber;
}
}
///
/// A static class that manages a quest log. It uses the Lua "Item[]" table, where each item in
/// the table whose 'Is Item' field is false represents a quest. This makes it easy to manage quests
/// in Chat Mapper by adding, removing, and modifying items in the built-in Item[] table. The name
/// of the item is the title of the quest. (Note that the Chat Mapper simulator doesn't have a
/// quest system, so it treats elements of the Item[] table as items.)
///
/// This class uses the following fields in the Item[] table, which is also aliased as Quest[]:
///
/// - Display Name: (optional) Name to use in UIs. If blank or not present, UIs use Name field.
/// - State (if using Chat Mapper, add this custom field or use the Dialogue System template
/// project)
/// - Valid values (case-sensitive): unassigned, active, success,
/// failure, or done
/// - Description: The description of the quest
/// - Success Description (optional): The description to be displayed when the quest has been
/// successfully completed
/// - Failure Description (optional): The description to be displayed when the quest has ended
/// in failure
///
/// Note: done is essentially equivalent to success. In the remainder of the Dialogue
/// System's documentation, either done or success may be used in examples, but when
/// using the QuestLog class, they both correspond to the same enum state, QuestState.Success.
///
/// As an example, you might define a simple quest like this:
///
/// - Item["Kill 5 Rats"]
/// - State = "unassigned"
/// - Description = "The baker asked me to bring him 5 rat corpses to make a pie."
/// - Success Description = "I brought the baker 5 dead rats, and we ate a delicious pie!"
/// - Failure Description = "I freed the Pied Piper from jail. He took all the rats. No pie for me...."
///
/// This class provides methods to add and delete quests, get and set their state, and get
/// their descriptions.
///
/// Note that quest states are usually updated during conversations. In most cases, you will
/// probably set quest states in Lua code during conversations, so you may never need to use
/// many of the methods in this class.
///
/// The UnityQuestLogWindow provides a quest log window using Unity GUI. You can use it as-is
/// or use it as a template for implementing your own quest log window in another GUI system
/// such as NGUI.
///
public static class QuestLog
{
///
/// Constant state string for unassigned quests.
///
public const string UnassignedStateString = "unassigned";
///
/// Constant state string for active quests.
///
public const string ActiveStateString = "active";
///
/// Constant state string for successfully-completed quests.
///
public const string SuccessStateString = "success";
///
/// Constant state string for quests ending in failure.
///
public const string FailureStateString = "failure";
///
/// Constant state string for quests that were abandoned.
///
public const string AbandonedStateString = "abandoned";
///
/// Constant state string for quests that are grantable.
/// This state isn't used by the Dialogue System, but it's made available for those who want to use it.
///
public const string GrantableStateString = "grantable";
///
/// Constant state string for quests that are waiting to return to NPC.
/// This state isn't used by the Dialogue System, but it's made available for those who want to use it.
///
public const string ReturnToNPCStateString = "returnToNPC";
///
/// Constant state string for quests that are done, if you want to track done instead of success/failure.
/// This is essentially the same as success, and corresponds to the same enum value, QuestState.Success
///
public const string DoneStateString = "done";
///
/// You can reassign this delegate method to override the default conversion of
/// strings to QuestStates.
///
public static StringToQuestStateDelegate StringToState = DefaultStringToState;
public static QuestStateToStringDelegate StateToString = DefaultStateToString;
///
/// You can assign a method to override the default CurrentQuestState.
///
public static CurrentQuestStateDelegate CurrentQuestStateOverride = null;
///
/// You can assign a method to override the default SetQuestState.
///
public static SetQuestStateDelegate SetQuestStateOverride = null;
///
/// You can assign a method to override the default CurrentQuestEntryState.
///
public static CurrentQuestEntryStateDelegate CurrentQuestEntryStateOverride = null;
///
/// You can assign a method to override the default SetQuestEntryState.
///
public static SetQuestEntryStateDelegate SetQuestEntryStateOverride = null;
///
/// Set true to allow only one quest to be tracked at a time.
///
public static bool trackOneQuestAtATime = false;
public static void RegisterQuestLogFunctions()
{
// Unity 2017.3 bug IL2CPP can't do lambdas:
//Lua.RegisterFunction("CurrentQuestState", null, SymbolExtensions.GetMethodInfo(() => CurrentQuestState(string.Empty)));
//Lua.RegisterFunction("CurrentQuestEntryState", null, SymbolExtensions.GetMethodInfo(() => CurrentQuestEntryState(string.Empty, (double)0)));
//Lua.RegisterFunction("SetQuestState", null, SymbolExtensions.GetMethodInfo(() => SetQuestState(string.Empty, string.Empty)));
//Lua.RegisterFunction("SetQuestEntryState", null, SymbolExtensions.GetMethodInfo(() => SetQuestEntryState(string.Empty, (double)0, string.Empty)));
Lua.RegisterFunction("CurrentQuestState", null, typeof(QuestLog).GetMethod("CurrentQuestState"));
Lua.RegisterFunction("CurrentQuestEntryState", null, typeof(QuestLog).GetMethod("CurrentQuestEntryState"));
Lua.RegisterFunction("SetQuestState", null, typeof(QuestLog).GetMethod("SetQuestState", new[] { typeof(string), typeof(string) }));
Lua.RegisterFunction("SetQuestEntryState", null, typeof(QuestLog).GetMethod("SetQuestEntryState", new[] { typeof(string), typeof(double), typeof(string) }));
Lua.RegisterFunction("UpdateQuestIndicators", null, typeof(QuestLog).GetMethod("UpdateQuestIndicators", new[] { typeof(string) }));
}
///
/// Adds a quest to the Lua Item[] table.
///
///
/// Name of the quest.
///
///
/// Description of the quest when active.
///
///
/// Description of the quest when successfully completed.
///
///
/// Description of the quest when completed in failure.
///
///
/// Quest state.
///
///
/// QuestLog.AddQuest("Kill 5 Rats", "The baker asked me to bring 5 rat corpses.", QuestState.Unassigned);
///
public static void AddQuest(string questName, string description, string successDescription, string failureDescription, QuestState state)
{
if (!string.IsNullOrEmpty(questName))
{
Lua.Run(string.Format("Item[\"{0}\"] = {{ Name = \"{1}\", Is_Item = false, Description = \"{2}\", Success_Description = \"{3}\", Failure_Description = \"{4}\", State = \"{5}\" }}",
new System.Object[] { DialogueLua.StringToTableIndex(questName),
DialogueLua.DoubleQuotesToSingle(questName),
DialogueLua.DoubleQuotesToSingle(description),
DialogueLua.DoubleQuotesToSingle(successDescription),
DialogueLua.DoubleQuotesToSingle(failureDescription),
StateToString(state) }),
DialogueDebug.logInfo);
}
}
///
/// Adds a quest to the Lua Item[] table.
///
///
/// Name of the quest.
///
///
/// Description of the quest.
///
///
/// Quest state.
///
///
/// QuestLog.AddQuest("Kill 5 Rats", "The baker asked me to bring 5 rat corpses.", QuestState.Unassigned);
///
public static void AddQuest(string questName, string description, QuestState state)
{
if (!string.IsNullOrEmpty(questName))
{
Lua.Run(string.Format("Item[\"{0}\"] = {{ Name = \"{1}\", Is_Item = false, Description = \"{2}\", State = \"{3}\" }}",
new System.Object[] { DialogueLua.StringToTableIndex(questName),
DialogueLua.DoubleQuotesToSingle(questName),
DialogueLua.DoubleQuotesToSingle(description),
StateToString(state) }),
DialogueDebug.logInfo);
}
}
///
/// Adds a quest to the Lua Item[] table, and sets the state to Unassigned.
///
///
/// Name of the quest.
///
///
/// Description of the quest.
///
///
/// QuestLog.AddQuest("Kill 5 Rats", "The baker asked me to bring 5 rat corpses.");
///
public static void AddQuest(string questName, string description)
{
AddQuest(questName, description, QuestState.Unassigned);
}
///
/// Deletes a quest from the Lua Item[] table. Use this method if you want to remove a quest entirely.
/// If you just want to set the state of a quest, use SetQuestState.
///
///
/// Name of the quest.
///
///
/// QuestLog.RemoveQuest("Kill 5 Rats");
///
public static void DeleteQuest(string questName)
{
if (!string.IsNullOrEmpty(questName))
{
Lua.Run(string.Format("Item[\"{0}\"] = nil", new System.Object[] { DialogueLua.StringToTableIndex(questName) }), DialogueDebug.logInfo);
}
}
///
/// Gets the quest state.
///
///
/// The quest state.
///
///
/// Name of the quest.
///
///
/// if (QuestLog.QuestState("Kill 5 Rats") == QuestState.Active) {
/// Smith.Say("Killing rats, eh? Here, take this hammer.");
/// }
///
public static QuestState GetQuestState(string questName)
{
return StringToState(CurrentQuestState(questName)); //---Was: DialogueLua.GetQuestField(questName, "State").AsString);
}
///
/// Gets the quest state.
///
/// Name of the quest.
/// The quest state string ("unassigned", "success", etc.).
public static string CurrentQuestState(string questName)
{
if (CurrentQuestStateOverride != null)
{
return CurrentQuestStateOverride(questName);
}
else
{
return DefaultCurrentQuestState(questName);
}
}
///
/// Default built-in version of CurrentQuestState.
///
public static string DefaultCurrentQuestState(string questName)
{
return DialogueLua.GetQuestField(questName, "State").asString;
}
///
/// Sets the quest state.
///
///
/// Name of the quest.
///
///
/// New state.
///
///
/// if (PiedPiperIsFree) {
/// QuestLog.SetQuestState("Kill 5 Rats", QuestState.Failure);
/// }
///
public static void SetQuestState(string questName, QuestState state)
{
SetQuestState(questName, StateToString(state));
}
///
/// Sets the quest state, using the override delegate if assigned; otherwise
/// using the default method DefaultSetQuestState.
///
/// Name of the quest.
/// New state.
public static void SetQuestState(string questName, string state)
{
if (SetQuestStateOverride != null)
{
SetQuestStateOverride(questName, state);
}
else
{
DefaultSetQuestState(questName, state);
}
}
///
/// Default built-in method to set quest state.
///
public static void DefaultSetQuestState(string questName, string state)
{
if (DialogueLua.DoesTableElementExist("Quest", questName))
{
DialogueLua.SetQuestField(questName, "State", state);
SendUpdateTracker();
InformQuestStateChange(questName);
}
else
{
if (DialogueDebug.logWarnings) Debug.LogWarning("Dialogue System: Quest '" + questName + "' doesn't exist. Can't set state to " + state);
}
}
private static void SendUpdateTracker()
{
DialogueManager.SendUpdateTracker();
}
public static void InformQuestStateChange(string questName)
{
DialogueManager.instance.BroadcastMessage(DialogueSystemMessages.OnQuestStateChange, questName, SendMessageOptions.DontRequireReceiver);
}
public static void InformQuestEntryStateChange(string questName, int entryNumber)
{
DialogueManager.instance.BroadcastMessage(DialogueSystemMessages.OnQuestEntryStateChange, new QuestEntryArgs(questName, entryNumber), SendMessageOptions.DontRequireReceiver);
}
///
/// Reports whether a quest is unassigned.
///
///
/// true if the quest is unassigned; otherwise, false.
///
///
/// Name of the quest.
///
public static bool IsQuestUnassigned(string questName)
{
return GetQuestState(questName) == QuestState.Unassigned;
}
///
/// Reports whether a quest is active.
///
///
/// true if the quest is active; otherwise, false.
///
///
/// Name of the quest.
///
public static bool IsQuestActive(string questName)
{
return GetQuestState(questName) == QuestState.Active;
}
///
/// Reports whether a quest was successfully completed.
///
///
/// true if the quest was successfully completed; otherwise, false.
///
///
/// Name of the quest.
///
public static bool IsQuestSuccessful(string questName)
{
return GetQuestState(questName) == QuestState.Success;
}
///
/// Reports whether a quest ended in failure.
///
///
/// true if the quest ended in failure; otherwise, false.
///
///
/// Name of the quest.
///
public static bool IsQuestFailed(string questName)
{
return GetQuestState(questName) == QuestState.Failure;
}
///
/// Reports whether a quest was abandoned (i.e., in the Abandoned state).
///
/// true if the quest was abandoned; otherwise, false.
/// Name of the quest.
public static bool IsQuestAbandoned(string questName)
{
return GetQuestState(questName) == QuestState.Abandoned;
}
///
/// Reports whether a quest is done, either successful or failed.
///
///
/// true if the quest is done; otherwise, false.
///
///
/// Name of the quest.
///
public static bool IsQuestDone(string questName)
{
QuestState state = GetQuestState(questName);
return ((state == QuestState.Success) || (state == QuestState.Failure));
}
///
/// Reports whether a quest's current state is one of the states marked in a state bit mask.
///
///
/// true if the quest's current state is in the state bit mask.
///
///
/// Name of the quest.
///
///
/// A QuestState bit mask (e.g., QuestState.Success | QuestState.Failure).
///
public static bool IsQuestInStateMask(string questName, QuestState stateMask)
{
QuestState state = GetQuestState(questName);
return ((stateMask & state) == state);
}
///
/// Reports whether a quest entry's current state is one of the states marked in a state bit mask.
///
///
/// true if the quest entry's current state is in the state bit mask.
///
///
/// Name of the quest.
///
///
/// Quest entry number.
///
///
/// A QuestState bit mask (e.g., QuestState.Success | QuestState.Failure).
///
public static bool IsQuestEntryInStateMask(string questName, int entryNumber, QuestState stateMask)
{
QuestState state = GetQuestEntryState(questName, entryNumber);
return ((stateMask & state) == state);
}
///
/// Starts a quest by setting its state to active.
///
///
/// Name of the quest.
///
///
/// StartQuest("Kill 5 Rats");
///
public static void StartQuest(string questName)
{
SetQuestState(questName, QuestState.Active);
}
///
/// Marks a quest successful.
///
///
/// Name of the quest.
///
public static void CompleteQuest(string questName)
{
SetQuestState(questName, QuestState.Success);
}
///
/// Marks a quest as failed.
///
///
/// Name of the quest.
///
public static void FailQuest(string questName)
{
SetQuestState(questName, QuestState.Failure);
}
///
/// Marks a quest as abandoned (i.e., in the Abandoned state).
///
/// Name of the quest.
public static void AbandonQuest(string questName)
{
SetQuestState(questName, QuestState.Abandoned);
}
///
/// Converts a string representation into a state enum value.
///
///
/// The state (e.g., QuestState.Active).
///
///
/// The string representation (e.g., "active").
///
public static QuestState DefaultStringToState(string s)
{
if (string.Equals(s, ActiveStateString)) return QuestState.Active;
if (string.Equals(s, SuccessStateString) || string.Equals(s, DoneStateString)) return QuestState.Success;
if (string.Equals(s, FailureStateString)) return QuestState.Failure;
if (string.Equals(s, AbandonedStateString)) return QuestState.Abandoned;
if (string.Equals(s, GrantableStateString)) return QuestState.Grantable;
if (string.Equals(s, ReturnToNPCStateString)) return QuestState.ReturnToNPC;
return QuestState.Unassigned;
}
public static string DefaultStateToString(QuestState state)
{
switch (state)
{
default:
case QuestState.Unassigned: return UnassignedStateString;
case QuestState.Active: return ActiveStateString;
case QuestState.Success: return SuccessStateString;
case QuestState.Failure: return FailureStateString;
case QuestState.Abandoned: return AbandonedStateString;
case QuestState.Grantable: return GrantableStateString;
case QuestState.ReturnToNPC: return ReturnToNPCStateString;
}
}
/////
///// Converts a state to its string representation.
/////
/////
///// The string representation (e.g., "active").
/////
/////
///// The state (e.g., QuestState.Active).
/////
//public static string StateToString(QuestState state)
//{
// switch (state)
// {
// case QuestState.Unassigned: return UnassignedStateString;
// case QuestState.Active: return ActiveStateString;
// case QuestState.Success: return SuccessStateString;
// case QuestState.Failure: return FailureStateString;
// case QuestState.Abandoned: return AbandonedStateString;
// case QuestState.Grantable: return GrantableStateString;
// case QuestState.ReturnToNPC: return ReturnToNPCStateString;
// default: return UnassignedStateString;
// }
//}
///
/// Gets the localized quest display name.
///
///
/// The quest title (display name) in the current language.
///
///
/// Name of the quest.
///
public static string GetQuestTitle(string questName)
{
var title = DialogueLua.GetLocalizedQuestField(questName, "Display Name").asString;
if (string.IsNullOrEmpty(title)) title = DialogueLua.GetLocalizedQuestField(questName, "Name").asString;
return title;
}
///
/// Gets a quest description, based on the current state of the quest (i.e., SuccessDescription, FailureDescription, or just Description).
///
///
/// The quest description.
///
///
/// Name of the quest.
///
///
/// GUILayout.Label("Objective: " + QuestLog.GetQuestDescription("Kill 5 Rats"));
///
public static string GetQuestDescription(string questName)
{
switch (GetQuestState(questName))
{
case QuestState.Success:
return GetQuestDescription(questName, QuestState.Success) ?? GetQuestDescription(questName, QuestState.Active);
case QuestState.Failure:
return GetQuestDescription(questName, QuestState.Failure) ?? GetQuestDescription(questName, QuestState.Active);
default:
return GetQuestDescription(questName, QuestState.Active);
}
}
///
/// Gets the localized quest description for a specific state.
///
///
/// The quest description.
///
///
/// Name of the quest.
///
///
/// State to check.
///
public static string GetQuestDescription(string questName, QuestState state)
{
string descriptionFieldName = GetDefaultDescriptionFieldForState(state);
string result = DialogueLua.GetLocalizedQuestField(questName, descriptionFieldName).asString;
return (string.Equals(result, "nil") || string.IsNullOrEmpty(result)) ? null : result;
}
private static string GetDefaultDescriptionFieldForState(QuestState state)
{
switch (state)
{
case QuestState.Success:
return "Success_Description";
case QuestState.Failure:
return "Failure_Description";
default:
return "Description";
}
}
///
/// Sets the quest description for a specified state.
///
///
/// Name of the quest.
///
///
/// Set the description for this state (i.e., regular, success, or failure).
///
///
/// The description.
///
public static void SetQuestDescription(string questName, QuestState state, string description)
{
if (DialogueLua.DoesTableElementExist("Quest", questName))
{
DialogueLua.SetQuestField(questName, GetDefaultDescriptionFieldForState(state), description);
}
}
///
/// Gets the quest abandon sequence. The QuestLogWindow plays this sequence when the player
/// abandons a quest.
///
/// The quest abandon sequence.
/// Quest name.
public static string GetQuestAbandonSequence(string questName)
{
return DialogueLua.GetLocalizedQuestField(questName, "Abandon Sequence").asString;
}
///
/// Sets the quest abandon sequence. The QuestLogWindow plays this sequence when the
/// player abandons a quest.
///
/// Quest name.
/// Sequence to play when the quest is abandoned.
public static void SetQuestAbandonSequence(string questName, string sequence)
{
DialogueLua.SetLocalizedQuestField(questName, "Abandon Sequence", sequence);
}
///
/// Gets the quest entry count.
///
/// The quest entry count.
/// Name of the quest.
public static int GetQuestEntryCount(string questName)
{
return DialogueLua.GetQuestField(questName, "Entry_Count").asInt;
}
///
/// Adds a quest entry to a quest.
///
/// Name of the quest.
/// Entry number.
/// The quest entry description.
public static void AddQuestEntry(string questName, string description)
{
if (DialogueLua.DoesTableElementExist("Quest", questName))
{
int entryCount = GetQuestEntryCount(questName);
entryCount++;
DialogueLua.SetQuestField(questName, "Entry_Count", entryCount);
string entryFieldName = GetEntryFieldName(entryCount);
DialogueLua.SetQuestField(questName, entryFieldName, DialogueLua.DoubleQuotesToSingle(description));
string entryStateFieldName = GetEntryStateFieldName(entryCount);
DialogueLua.SetQuestField(questName, entryStateFieldName, "unassigned");
}
}
///
/// Gets the localized quest entry description.
///
/// The quest entry description.
/// Name of the quest.
/// Entry number.
public static string GetQuestEntry(string questName, int entryNumber)
{
var state = GetQuestEntryState(questName, entryNumber);
string entryFieldName = GetEntryFieldName(entryNumber);
if (state == QuestState.Success && DialogueLua.DoesTableElementExist("Quest", entryFieldName + " Success"))
{
entryFieldName += " Success";
}
else if (state == QuestState.Failure && DialogueLua.DoesTableElementExist("Quest", entryFieldName + " Failure"))
{
entryFieldName += " Failure";
}
return DialogueLua.GetLocalizedQuestField(questName, entryFieldName).asString;
}
///
/// Sets the localized quest entry description.
///
/// Name of the quest.
/// Entry number.
/// The quest entry description.
public static void SetQuestEntry(string questName, int entryNumber, string description)
{
string entryFieldName = GetEntryFieldName(entryNumber);
DialogueLua.SetLocalizedQuestField(questName, entryFieldName, DialogueLua.DoubleQuotesToSingle(description));
}
///
/// Gets the state of the quest entry.
///
/// The quest entry state.
/// Name of the quest.
/// Entry number.
public static QuestState GetQuestEntryState(string questName, int entryNumber)
{
//---Was: string s = DialogueLua.GetQuestField(questName, GetEntryStateFieldName(entryNumber)).AsString;
//--- return StringToState(s);
return StringToState(CurrentQuestEntryState(questName, entryNumber));
}
///
/// Gets the state of the quest entry.
///
/// The quest entry state.
/// Name of the quest.
/// Entry number.
public static string CurrentQuestEntryState(string questName, double entryNumber)
{
if (CurrentQuestEntryStateOverride != null)
{
return CurrentQuestEntryStateOverride(questName, (int)entryNumber);
}
else
{
return DefaultCurrentQuestEntryState(questName, (int)entryNumber);
}
}
///
/// Default built-in implementation of CurrentQuestEntryState.
///
public static string DefaultCurrentQuestEntryState(string questName, int entryNumber)
{
return DialogueLua.GetQuestField(questName, GetEntryStateFieldName((int)entryNumber)).asString;
}
///
/// Sets the state of the quest entry.
///
/// Name of the quest.
/// Entry number.
/// State.
public static void SetQuestEntryState(string questName, int entryNumber, QuestState state)
{
SetQuestEntryState(questName, entryNumber, StateToString(state));
}
///
/// Sets the state of a quest entry.
///
/// Name of the quest.
/// Entry number.
/// State.
public static void SetQuestEntryState(string questName, double entryNumber, string state)
{
if (SetQuestEntryStateOverride != null)
{
SetQuestEntryStateOverride(questName, (int)entryNumber, state);
}
else
{
DefaultSetQuestEntryState(questName, (int)entryNumber, state);
}
}
///
/// Default built-in method to set quest entry state.
///
public static void DefaultSetQuestEntryState(string questName, int entryNumber, string state)
{
if (DialogueLua.DoesTableElementExist("Quest", questName))
{
DialogueLua.SetQuestField(questName, GetEntryStateFieldName((int)entryNumber), state);
InformQuestStateChange(questName);
InformQuestEntryStateChange(questName, (int)entryNumber);
SendUpdateTracker();
}
else
{
if (DialogueDebug.logWarnings) Debug.LogWarning("Dialogue System: Quest '" + questName + "' doesn't exist. Can't set entry " + (int)entryNumber + " state to " + state);
}
}
public static string GetEntryFieldName(int entryNumber)
{
return string.Format("Entry_{0}", new System.Object[] { entryNumber });
}
public static string GetEntryStateFieldName(int entryNumber)
{
return string.Format("Entry_{0}_State", new System.Object[] { entryNumber });
}
///
/// Determines if quest tracking is available (that is, if the quest has a "Trackable" field).
///
/// true if quest tracking is available; otherwise, false.
/// Quest name.
public static bool IsQuestTrackingAvailable(string questName)
{
return DialogueLua.GetQuestField(questName, "Trackable").asBool;
}
///
/// Specifies whether quest tracking is available (that is, if the quest has a "Trackable" field).
///
/// Quest name.
/// Trackable or not.
public static void SetQuestTrackingAvailable(string questName, bool value)
{
if (DialogueLua.DoesTableElementExist("Quest", questName))
{
DialogueLua.SetQuestField(questName, "Trackable", value);
SendUpdateTracker();
}
}
///
/// Determines if tracking is enabled for a quest.
///
/// true if tracking enabled on the specified quest; otherwise, false.
/// Quest name.
public static bool IsQuestTrackingEnabled(string questName)
{
return IsQuestTrackingAvailable(questName)
? DialogueLua.GetQuestField(questName, "Track").asBool
: false;
}
///
/// Sets quest tracking on or off (by setting the Track field). If turning on tracking
/// and tracking is currently not available (Trackable field is false), this also sets
/// the Trackable field true.
///
/// Quest name.
/// If set to true, tracking is enabled.
public static void SetQuestTracking(string questName, bool value)
{
if (DialogueLua.DoesTableElementExist("Quest", questName))
{
if (value == true)
{
// If only one quest can be tracked at time, untrack all others:
if (trackOneQuestAtATime)
{
var quests = GetAllQuests();
foreach (var otherQuestName in quests)
{
if (string.Equals(otherQuestName, questName)) continue;
if (IsQuestTrackingEnabled(otherQuestName))
{
DialogueLua.SetQuestField(otherQuestName, "Track", false);
DialogueManager.instance.BroadcastMessage(DialogueSystemMessages.OnQuestTrackingDisabled, otherQuestName, SendMessageOptions.DontRequireReceiver);
}
}
}
// Make sure tracking is set to be available for this quest:
if (!IsQuestTrackingAvailable(questName))
{
SetQuestTrackingAvailable(questName, true);
}
}
// Track this quest:
DialogueLua.SetQuestField(questName, "Track", value);
SendUpdateTracker();
DialogueManager.instance.BroadcastMessage(value ? DialogueSystemMessages.OnQuestTrackingEnabled : DialogueSystemMessages.OnQuestTrackingDisabled, questName, SendMessageOptions.DontRequireReceiver);
}
}
///
/// Determines if a quest is abandonable (that is, is has a field named "Abandonable" that's true.)
///
/// true if the quest is abandonable; otherwise, false.
/// Quest name.
public static bool IsQuestAbandonable(string questName)
{
return DialogueLua.GetQuestField(questName, "Abandonable").asBool;
}
///
/// Returns true if quest has a field named "Visible" that is currently true or doesn't have the field.
///
public static bool IsQuestVisible(string questName)
{
var result = Lua.Run($"return Quest[{DialogueLua.StringToTableIndex(questName)}].Visible").asString;
if (string.IsNullOrEmpty(result) || string.Equals(result, "nil")) return true;
return string.Compare(result, "false", true) == 0;
}
///
/// Sets a quest's Visible field true or false.
///
public static void SetQuestVisibility(string questName)
{
if (DialogueLua.DoesTableElementExist("Quest", questName))
{
DialogueLua.SetQuestField(questName, "Visible", true);
}
}
///
/// Returns true if quest has a field named "Viewed" that is currently true.
/// Used if QuestLogWindow.newQuestText is not blank.
///
public static bool WasQuestViewed(string questName)
{
return DialogueLua.GetQuestField(questName, "Viewed").asBool;
}
///
/// Marks a quest as viewed (i.e., in the quest log window).
/// Generally only set/used when QuestLogWindow.newQuestText is not blank.
///
///
public static void MarkQuestViewed(string questName)
{
if (DialogueLua.DoesTableElementExist("Quest", questName))
{
DialogueLua.SetQuestField(questName, "Viewed", true);
}
}
///
/// Gets the group that a quest belongs to.
///
/// The quest group name, or empty string if no group.
/// Quest name.
public static string GetQuestGroup(string questName)
{
return DialogueLua.GetLocalizedQuestField(questName, "Group").asString;
}
public static string GetQuestGroupDisplayName(string questName)
{
var result = DialogueLua.GetLocalizedQuestField(questName, "Group Display Name").asString;
if (string.IsNullOrEmpty(result) || result == "nil") result = GetQuestGroup(questName);
return result;
}
///
/// Gets all quest group names.
///
/// The group names for active quests, sorted by name.
public static string[] GetAllGroups()
{
return GetAllGroups(QuestState.Active, true);
}
///
/// Gets all quest group names.
///
/// The group names, sorted by name.
/// Flags for the quest states to filter.
public static string[] GetAllGroups(QuestState flags)
{
return GetAllGroups(flags, true);
}
///
/// Gets all quest group names.
///
/// The group names.
/// Flags for the quest states to filter.
/// If set to true sort by group name.
public static string[] GetAllGroups(QuestState flags, bool sortByGroupName)
{
List groups = new List();
LuaTableWrapper itemTable = Lua.Run("return Item").asTable;
if (!itemTable.isValid)
{
if (DialogueDebug.logWarnings) Debug.LogWarning(string.Format("{0}: Quest Log couldn't access Lua Item[] table. Has the Dialogue Manager loaded a database yet?", new System.Object[] { DialogueDebug.Prefix }));
return groups.ToArray();
}
foreach (var itemTableValue in itemTable.values)
{
LuaTableWrapper fields = itemTableValue as LuaTableWrapper;
if (fields == null) continue;
string questName = null;
string group = null;
bool isItem = false;
try
{
object questNameObject = fields["Name"];
questName = (questNameObject != null) ? questNameObject.ToString() : string.Empty;
object groupObject = fields["Group"];
group = (groupObject != null) ? groupObject.ToString() : string.Empty;
isItem = false;
object isItemObject = fields["Is_Item"];
if (isItemObject != null)
{
if (isItemObject.GetType() == typeof(bool))
{
isItem = (bool)isItemObject;
}
else
{
isItem = Tools.StringToBool(isItemObject.ToString());
}
}
}
catch { }
if (!isItem)
{
if (!groups.Contains(group) && IsQuestInStateMask(questName, flags))
{
groups.Add(group);
}
}
}
if (sortByGroupName) groups.Sort();
return groups.ToArray();
}
///
/// Gets an array of all active quests.
///
///
/// The names of all active quests, sorted by Name.
///
///
/// string[] activeQuests = QuestLog.GetAllQuests();
///
public static string[] GetAllQuests()
{
return GetAllQuests(QuestState.Active, true, null);
}
///
/// Gets an array of all quests matching the specified state bitmask.
///
/// The names of all quests matching the specified state bitmask, sorted by Name.
/// A bitmask of QuestState values.
///
/// string[] completedQuests = QuestLog.GetAllQuests( QuestState.Success | QuestState.Failure );
///
public static string[] GetAllQuests(QuestState flags)
{
return GetAllQuests(flags, true, null);
}
///
/// Gets an array of all quests matching the specified state bitmask.
///
/// The names of all quests matching the specified state bitmask.
/// A bitmask of QuestState values.
/// If `true`, sorts the names by name.
///
/// string[] completedQuests = QuestLog.GetAllQuests( QuestState.Success | QuestState.Failure, true );
///
public static string[] GetAllQuests(QuestState flags, bool sortByName)
{
return GetAllQuests(flags, sortByName, null);
}
///
/// Gets an array of all quests matching the specified state bitmask and in the specified group.
///
/// The names of all quests matching the specified state bitmask.
/// A bitmask of QuestState values.
/// If `true`, sorts the names by name.
/// If not null, return only quests in the specified group.
///
/// string[] completedQuests = QuestLog.GetAllQuests( QuestState.Success | QuestState.Failure, true );
///
public static string[] GetAllQuests(QuestState flags, bool sortByName, string group)
{
List questNames = new List();
LuaTableWrapper itemTable = Lua.Run("return Item").asTable;
if (!itemTable.isValid)
{
if (DialogueDebug.logWarnings) Debug.LogWarning(string.Format("{0}: Quest Log couldn't access Lua Item[] table. Has the Dialogue Manager loaded a database yet?", new System.Object[] { DialogueDebug.Prefix }));
return questNames.ToArray();
}
var filterGroup = (group != null);
foreach (var itemTableValue in itemTable.values)
{
LuaTableWrapper fields = itemTableValue as LuaTableWrapper;
if (fields == null) continue;
string questName = null;
string thisGroup = null;
bool isItem = false;
try
{
object questNameObject = fields["Name"];
questName = (questNameObject != null) ? questNameObject.ToString() : string.Empty;
if (filterGroup)
{
object groupObject = fields["Group"];
thisGroup = (groupObject != null) ? groupObject.ToString() : string.Empty;
}
isItem = false;
object isItemObject = fields["Is_Item"];
if (isItemObject != null)
{
if (isItemObject.GetType() == typeof(bool))
{
isItem = (bool)isItemObject;
}
else
{
isItem = Tools.StringToBool(isItemObject.ToString());
}
}
}
catch { }
if (!isItem)
{
if (string.IsNullOrEmpty(questName))
{
if (DialogueDebug.logWarnings) Debug.LogWarning(string.Format("{0}: A quest name (item name in Item[] table) is null or empty", new System.Object[] { DialogueDebug.Prefix }));
}
else if (!filterGroup || string.Equals(group, thisGroup))
{
if (IsQuestInStateMask(questName, flags))
{
questNames.Add(questName);
}
}
}
}
if (sortByName) questNames.Sort();
return questNames.ToArray();
}
///
/// Gets all quests (including their group names) in a specified state.
///
/// An array of QuestGroupRecord elements.
/// A bitmask of QuestState values.
/// Sort by group and name.
public static QuestGroupRecord[] GetAllGroupsAndQuests(QuestState flags, bool sort = true)
{
List list = new List();
LuaTableWrapper itemTable = Lua.Run("return Item").asTable;
if (!itemTable.isValid)
{
if (DialogueDebug.logWarnings) Debug.LogWarning(string.Format("{0}: Quest Log couldn't access Lua Item[] table. Has the Dialogue Manager loaded a database yet?", new System.Object[] { DialogueDebug.Prefix }));
return list.ToArray();
}
foreach (var itemTableValue in itemTable.values)
{
LuaTableWrapper fields = itemTableValue as LuaTableWrapper;
if (fields == null) continue;
string questName = null;
string group = null;
bool isItem = false;
try
{
object questNameObject = fields["Name"];
questName = (questNameObject != null) ? questNameObject.ToString() : string.Empty;
object groupObject = fields["Group"];
group = (groupObject != null) ? groupObject.ToString() : string.Empty;
isItem = false;
object isItemObject = fields["Is_Item"];
if (isItemObject != null)
{
if (isItemObject.GetType() == typeof(bool))
{
isItem = (bool)isItemObject;
}
else
{
isItem = Tools.StringToBool(isItemObject.ToString());
}
}
}
catch { }
if (!isItem)
{
if (string.IsNullOrEmpty(questName))
{
if (DialogueDebug.logWarnings) Debug.LogWarning(string.Format("{0}: A quest name (item name in Item[] table) is null or empty", new System.Object[] { DialogueDebug.Prefix }));
}
else if (IsQuestInStateMask(questName, flags))
{
list.Add(new QuestGroupRecord(group, questName));
}
}
}
if (sort) list.Sort();
return list.ToArray();
}
///
/// Quest changed delegate.
///
public delegate void QuestChangedDelegate(string questName, QuestState newState);
///
/// The quest watch item class is used internally by the QuestLog class to manage
/// Lua observers on quest states.
///
public class QuestWatchItem
{
private string questName;
private int entryNumber;
private LuaWatchFrequency frequency;
private string luaExpression;
private QuestChangedDelegate questChangedHandler;
public QuestWatchItem(string questName, LuaWatchFrequency frequency, QuestChangedDelegate questChangedHandler)
{
this.questName = questName;
this.entryNumber = 0;
this.frequency = frequency;
this.luaExpression = string.Format("return Item[\"{0}\"].State", new System.Object[] { DialogueLua.StringToTableIndex(questName) });
this.questChangedHandler = questChangedHandler;
DialogueManager.AddLuaObserver(luaExpression, frequency, OnLuaChanged);
}
public QuestWatchItem(string questName, int entryNumber, LuaWatchFrequency frequency, QuestChangedDelegate questChangedHandler)
{
this.questName = questName;
this.entryNumber = entryNumber;
this.frequency = frequency;
this.luaExpression = string.Format("return Item[\"{0}\"].Entry_{1}_State", new System.Object[] { DialogueLua.StringToTableIndex(questName), entryNumber });
this.questChangedHandler = questChangedHandler;
DialogueManager.AddLuaObserver(luaExpression, frequency, OnLuaChanged);
}
public bool Matches(string questName, LuaWatchFrequency frequency, QuestChangedDelegate questChangedHandler)
{
return string.Equals(questName, this.questName) && (frequency == this.frequency) && (questChangedHandler == this.questChangedHandler);
}
public bool Matches(string questName, int entryNumber, LuaWatchFrequency frequency, QuestChangedDelegate questChangedHandler)
{
return string.Equals(questName, this.questName) && (entryNumber == this.entryNumber) && (frequency == this.frequency) && (questChangedHandler == this.questChangedHandler);
}
public void StopObserving()
{
DialogueManager.RemoveLuaObserver(luaExpression, frequency, OnLuaChanged);
}
private void OnLuaChanged(LuaWatchItem luaWatchItem, Lua.Result newResult)
{
if (string.Equals(luaWatchItem.luaExpression, this.luaExpression) && (questChangedHandler != null))
{
questChangedHandler(questName, StringToState(newResult.asString));
}
}
}
///
/// The quest watch list.
///
private static readonly List questWatchList = new List();
///
/// Adds a quest state observer.
///
///
/// Name of the quest.
///
///
/// Frequency to check the quest state.
///
///
/// Delegate to call when the quest state changes. This should be in the form:
/// void MyDelegate(string questName, QuestState newState) {...}
///
public static void AddQuestStateObserver(string questName, LuaWatchFrequency frequency, QuestChangedDelegate questChangedHandler)
{
questWatchList.Add(new QuestWatchItem(questName, frequency, questChangedHandler));
}
///
/// Adds a quest state observer.
///
///
/// Name of the quest.
///
///
/// The entry number (1...Entry Count) in the quest.
///
///
/// Frequency to check the quest state.
///
///
/// Delegate to call when the quest state changes. This should be in the form:
/// void MyDelegate(string questName, QuestState newState) {...}
///
public static void AddQuestStateObserver(string questName, int entryNumber, LuaWatchFrequency frequency, QuestChangedDelegate questChangedHandler)
{
questWatchList.Add(new QuestWatchItem(questName, entryNumber, frequency, questChangedHandler));
}
///
/// Removes a quest state observer. To be removed, the questName, frequency, and delegate must
/// all match.
///
///
/// Name of the quest.
///
///
/// Frequency that the quest state is being checked.
///
///
/// Quest changed handler delegate.
///
public static void RemoveQuestStateObserver(string questName, LuaWatchFrequency frequency, QuestChangedDelegate questChangedHandler)
{
foreach (var questWatchItem in questWatchList)
{
if (questWatchItem.Matches(questName, frequency, questChangedHandler)) questWatchItem.StopObserving();
}
questWatchList.RemoveAll(questWatchItem => questWatchItem.Matches(questName, frequency, questChangedHandler));
}
///
/// Removes a quest state observer. To be removed, the questName, frequency, and delegate must
/// all match.
///
///
/// Name of the quest.
///
///
/// The entry number (1...Entry Count) in the quest.
///
///
/// Frequency that the quest state is being checked.
///
///
/// Quest changed handler delegate.
///
public static void RemoveQuestStateObserver(string questName, int entryNumber, LuaWatchFrequency frequency, QuestChangedDelegate questChangedHandler)
{
foreach (var questWatchItem in questWatchList)
{
if (questWatchItem.Matches(questName, entryNumber, frequency, questChangedHandler)) questWatchItem.StopObserving();
}
questWatchList.RemoveAll(questWatchItem => questWatchItem.Matches(questName, entryNumber, frequency, questChangedHandler));
}
///
/// Removes all quest state observers.
///
public static void RemoveAllQuestStateObservers()
{
foreach (var questWatchItem in questWatchList)
{
questWatchItem.StopObserving();
}
questWatchList.Clear();
}
///
/// Updates all quest state listeners who are listening for questName.
///
public static void UpdateQuestIndicators(string questName)
{
var dispatcher = PixelCrushers.GameObjectUtility.FindFirstObjectByType();
if (dispatcher != null) dispatcher.OnQuestStateChange(questName);
}
}
}