void IMessageHandler.OnMessage(MessageArgs messageArgs)
        {
            if (!isChecking || messageArgs.values == null || messageArgs.values.Length < 2 || requiredQuestID == null)
            {
                return;
            }
            var questID = messageArgs.parameter;

            if (!StringField.Equals(requiredQuestID, questID))
            {
                return;
            }
            var questNodeID = QuestMachineMessages.ArgToString(messageArgs.values[0]);

            if (!string.IsNullOrEmpty(questNodeID))
            {
                return;
            }
            var stateValue = messageArgs.values[1];
            var state      = (stateValue != null && stateValue.GetType() == typeof(QuestState)) ? (QuestState)stateValue : QuestState.WaitingToStart;

            if (state == requiredState)
            {
                SetTrue();
            }
        }
Пример #2
0
        //------------------------------------------------------------------
        // Load:

        private static void ReadQuestDataFromStream(BinaryReader binaryReader, Quest quest)
        {
            if (quest == null)
            {
                return;
            }
            var state = (QuestState)binaryReader.ReadByte();

            ReadTagDictionaryFromStream(binaryReader, quest.tagDictionary, quest.name);
            quest.questGiverID.value       = binaryReader.ReadString();
            quest.timesAccepted            = binaryReader.ReadInt32();
            quest.cooldownSecondsRemaining = (float)binaryReader.ReadDouble();
            quest.showInTrackHUD           = binaryReader.ReadBoolean();
            ReadConditionSetDataFromStream(binaryReader, quest.autostartConditionSet);
            ReadConditionSetDataFromStream(binaryReader, quest.offerConditionSet);
            if (state == QuestState.WaitingToStart)
            {
                quest.SetState(state, false);
                return;
            }

            // Don't load the info below if waiting to start:
            for (int i = 0; i < quest.counterList.Count; i++)
            {
                quest.counterList[i].SetValue(binaryReader.ReadInt32(), QuestCounterSetValueMode.DontInformListeners);
            }
            for (int i = 0; i < quest.nodeList.Count; i++)
            {
                ReadQuestNodeDataFromStream(binaryReader, quest.nodeList[i]);
            }
            ReadQuestIndicatorsFromStream(binaryReader, quest.indicatorStates);
            quest.SetRuntimeReferences();
            quest.SetState(state, false);
            QuestMachineMessages.QuestStateChanged(quest, quest.id, quest.GetState());
        }
Пример #3
0
        private bool IsRequiredValue(MessageArgs messageArgs)
        {
            if (value == null)
            {
                return(true);
            }
            if (value.valueType == MessageValueType.None)
            {
                return(true);
            }
            if (messageArgs.firstValue == null)
            {
                return(false);
            }
            switch (value.valueType)
            {
            case MessageValueType.String:
                return(QuestMachineMessages.ArgToString(messageArgs.firstValue) == runtimeStringValue);

            case MessageValueType.Int:
                return(QuestMachineMessages.ArgToInt(messageArgs.firstValue) == value.intValue);

            default:
                Debug.LogError("Quest Machine: Unhandled MessageValueType " + value.valueType + ". Please contact the developer.", quest);
                return(false);
            }
        }
Пример #4
0
        void IMessageHandler.OnMessage(MessageArgs messageArgs)
        {
            if (!isChecking)
            {
                return;
            }
            if (messageArgs.values == null || messageArgs.values.Length < 2 || requiredQuestID == null)
            {
                return;
            }
            var questID = messageArgs.parameter;

            if (!string.Equals(questID, StringField.GetStringValue(requiredQuestID)))
            {
                return;
            }
            var questNodeID = QuestMachineMessages.ArgToString(messageArgs.values[0]);

            if (!string.Equals(questNodeID, requiredQuestNodeID.value))
            {
                return;
            }
            var stateValue = messageArgs.values[1];
            var state      = (stateValue != null && stateValue.GetType() == typeof(QuestNodeState)) ? (QuestNodeState)stateValue : QuestNodeState.Inactive;

            if (state == requiredState)
            {
                SetTrue();
            }
        }
Пример #5
0
 protected virtual void ShowOfferQuest(Quest quest)
 {
     if (questDialogueUI == null)
     {
         if (Debug.isDebugBuild)
         {
             Debug.LogWarning("Quest Machine: There is no Quest Dialogue UI.", this);
         }
     }
     else if (quest == null)
     {
         if (Debug.isDebugBuild)
         {
             Debug.LogWarning("Quest Machine: The quest passed to ShowOfferQuest() is null.", this);
         }
     }
     else if (playerQuestListContainer == null)
     {
         if (Debug.isDebugBuild)
         {
             Debug.LogWarning("Quest Machine: There is no Player Quest List Container. Can't offer quest '" + quest.title + "'.", this);
         }
     }
     else
     {
         quest.greeterID = StringField.GetStringValue(playerTextInfo.id);
         QuestMachineMessages.DiscussQuest(player, this, id, quest.id);
         playerQuestListContainer.DeleteQuest(quest.id); // Clear any old instance of repeatable quests first.
         questDialogueUI.ShowOfferQuest(myQuestGiverTextInfo, quest, OnAcceptQuest, OnQuestBackButton);
         QuestMachineMessages.DiscussedQuest(player, this, id, quest.id);
     }
 }
Пример #6
0
        /// <summary>
        /// If onlyTrackOneQuestAtATime is true and the specified quest is
        /// now being tracked, disable tracking on other quests.
        /// </summary>
        /// <param name="questID"></param>
        public virtual void CheckTrackingToggles(string questID)
        {
            if (!onlyTrackOneQuestAtATime)
            {
                return;
            }
            var quest = FindQuest(questID);

            if (quest == null || !quest.showInTrackHUD)
            {
                return;
            }
            var changed = false;

            for (int i = 0; i < questList.Count; i++)
            {
                if (questList[i] == null || !questList[i].showInTrackHUD || Equals(questList[i].id, questID))
                {
                    continue;
                }
                questList[i].showInTrackHUD = false;
                changed = true;
            }
            if (changed)
            {
                QuestMachineMessages.RefreshUIs(quest);
            }
        }
 protected virtual void Awake()
 {
     myID = StringField.GetStringValue(QuestMachineMessages.GetID(gameObject));
     InitializeQuestIndicatorUI();
     InitializeStates();
     RegisterWithMessageSystem();
 }
Пример #8
0
        /// <summary>
        /// Adds an instance of a quest to a quester's list. If the quest's maxTimes are reached,
        /// deletes the quest from the giver. Otherwise starts cooldown timer until it can be
        /// given again.
        /// </summary>
        /// <param name="quest">Quest to give to quester.</param>
        /// <param name="questerTextInfo">Quester's text info.</param>
        /// <param name="questerQuestListContainer">Quester's quest list container.</param>
        public virtual void GiveQuestToQuester(Quest quest, QuestParticipantTextInfo questerTextInfo, QuestListContainer questerQuestListContainer)
        {
            if (quest == null)
            {
                Debug.LogWarning("Quest Machine: " + name + ".GiveQuestToQuester - quest is null.", this);
                return;
            }
            if (questerTextInfo == null)
            {
                Debug.LogWarning("Quest Machine: " + name + ".GiveQuestToQuester - questerTextInfo is null.", this);
                return;
            }
            if (questerQuestListContainer == null)
            {
                Debug.LogWarning("Quest Machine: " + name + ".GiveQuestToQuester - questerQuestListContainer is null.", this);
                return;
            }

            // Make a copy of the quest for the quester:
            var questInstance = quest.Clone();

            // Update the version on this QuestGiver:
            quest.timesAccepted++;
            if (quest.timesAccepted >= quest.maxTimes)
            {
                DeleteQuest(quest.id);
            }
            else
            {
                quest.StartCooldown();
            }

            // Add the copy to the quester and activate it:
            questInstance.AssignQuestGiver(myQuestGiverTextInfo);
            questInstance.AssignQuester(questerTextInfo);
            questInstance.timesAccepted = 1;
            if (questerQuestListContainer.questList.Count > 0)
            {
                for (int i = questerQuestListContainer.questList.Count - 1; i >= 0; i--)
                {
                    var inJournal = questerQuestListContainer.questList[i];
                    if (inJournal == null)
                    {
                        continue;
                    }
                    if (StringField.Equals(inJournal.id, quest.id) && inJournal.GetState() != QuestState.Active)
                    {
                        questInstance.timesAccepted++;
                        questerQuestListContainer.DeleteQuest(inJournal);
                    }
                }
            }
            questerQuestListContainer.deletedStaticQuests.Remove(StringField.GetStringValue(questInstance.id));
            questerQuestListContainer.AddQuest(questInstance);
            questInstance.SetState(QuestState.Active);
            QuestMachineMessages.RefreshIndicators(questInstance);
        }
Пример #9
0
        public void OnMessage(MessageArgs messageArgs)
        {
            if (QuestMachine.debug)
            {
                Debug.Log("Quest Machine: QuestCounter[" + name + "].OnMessage(" + messageArgs.message + ", " + messageArgs.parameter + ")", m_quest);
            }
            switch (messageArgs.message)
            {
            case DataSynchronizer.DataSourceValueChangedMessage:
                m_currentValue = messageArgs.intValue;
                break;

            case QuestMachineMessages.SetQuestCounterMessage:
                m_currentValue = messageArgs.intValue;
                break;

            case QuestMachineMessages.IncrementQuestCounterMessage:
                m_currentValue += messageArgs.intValue;
                break;

            default:
                if (messageEventList == null)
                {
                    break;
                }
                for (int i = 0; i < messageEventList.Count; i++)
                {
                    var messageEvent = messageEventList[i];
                    if (messageEvent != null && messageArgs.Matches(messageEvent.message, messageEvent.parameter) &&
                        QuestMachineMessages.IsRequiredID(messageArgs.sender, QuestMachineTags.ReplaceTags(messageEvent.senderID, m_quest)) &&
                        QuestMachineMessages.IsRequiredID(messageArgs.target, QuestMachineTags.ReplaceTags(messageEvent.targetID, m_quest)))
                    {
                        switch (messageEvent.operation)
                        {
                        case QuestCounterMessageEvent.Operation.ModifyByLiteralValue:
                            m_currentValue += messageEvent.literalValue;
                            break;

                        case QuestCounterMessageEvent.Operation.ModifyByParameter:
                            m_currentValue += messageArgs.intValue;
                            break;

                        case QuestCounterMessageEvent.Operation.SetToLiteralValue:
                            m_currentValue = messageEvent.literalValue;
                            break;

                        case QuestCounterMessageEvent.Operation.SetToParameter:
                            m_currentValue = messageArgs.intValue;
                            break;
                        }
                    }
                }
                break;
            }
            SetValue(m_currentValue, QuestCounterSetValueMode.DontInformDataSync);
        }
Пример #10
0
        /// <summary>
        /// Starts dialogue with the player. The content of the dialogue will depend on the quest giver's
        /// offerable quests and the player's quests.
        /// </summary>
        /// <param name="player">Player conversing with this QuestGiver. If null, searches the scene for a GameObject tagged Player.</param>
        public virtual void StartDialogue(GameObject player)
        {
            if (questDialogueUI == null && Debug.isDebugBuild)
            {
                Debug.LogWarning("Quest Machine: Can't start dialogue with " + name + ". Quest Giver doesn't have access to a quest dialogue UI.", this);
                return;
            }

            // If player isn't specified, find it in the scene and find relevant quest journal:
            if (player == null)
            {
                player = FindPlayerGameObject();
            }
            if (player == null && Debug.isDebugBuild)
            {
                Debug.LogWarning("Quest Machine: Can't start dialogue with " + name + ". No quester specified.", this);
                return;
            }
            playerQuestListContainer = player.GetComponent <QuestListContainer>();
            if (playerQuestListContainer == null)
            {
                var playerID = player.GetComponent <QuestMachineID>();
                if (playerID != null && playerID.questListContainer != null)
                {
                    playerQuestListContainer = playerID.questListContainer;
                }
                else
                {
                    var playerJournalObject = FindPlayerJournalGameObject();
                    playerQuestListContainer = (playerJournalObject != null) ? playerJournalObject.GetComponent <QuestListContainer>() : null;
                }
            }
            if (playerQuestListContainer == null && Debug.isDebugBuild)
            {
                Debug.LogWarning("Quest Machine: Can't start dialogue with " + name + ". Quester " + player.name + " doesn't have a Quest Journal and can't find one in scene.", this);
                return;
            }

            QuestMachineTags.fallbackTextTable = textTable;

            // Setup player info:
            this.player    = player;
            playerTextInfo = new QuestParticipantTextInfo(QuestMachineMessages.GetID(player), QuestMachineMessages.GetDisplayName(player), null, null);

            // Greet before recording quests in case Greet message changes a quest state:
            QuestMachineMessages.Greet(player, this, id);

            // Record quests related to this player and me:
            RecordQuestsByState();

            StartMostRelevantDialogue();

            // Note: Sends Greeted immediately after opening dialogue UI, not when closing it:
            QuestMachineMessages.Greeted(player, this, id);
        }
Пример #11
0
        public void OnToggleTracking(bool value, object data)
        {
            var quest = data as Quest;

            if (quest == null)
            {
                return;
            }
            quest.showInTrackHUD = value;
            QuestMachineMessages.RefreshUIs(quest);
        }
Пример #12
0
        /// <summary>
        /// Adds a quest to this quest giver's list.
        /// </summary>
        /// <param name="quest"></param>
        public override Quest AddQuest(Quest quest)
        {
            if (quest == null)
            {
                return(null);
            }
            var instance = base.AddQuest(quest);

            instance.AssignQuestGiver(myQuestGiverTextInfo);
            QuestMachineMessages.RefreshUIs(this);
            return(instance);
        }
Пример #13
0
 public override void Execute()
 {
     if (quest == null)
     {
         if (Debug.isDebugBuild)
         {
             Debug.LogWarning("Quest Machine: AlertQuestAction was passed a null quest.");
         }
         return;
     }
     QuestMachineMessages.QuestAlert(quest, quest.id, contentList);
 }
Пример #14
0
 public void ClearQuestIndicatorStates()
 {
     if (indicatorStates == null)
     {
         return;
     }
     foreach (var kvp in indicatorStates)
     {
         MessageSystem.SendMessageWithTarget(this, kvp.Key, QuestMachineMessages.SetIndicatorStateMessage, id, QuestIndicatorState.None);
     }
     indicatorStates.Clear();
     QuestMachineMessages.RefreshIndicators(questGiverID);
 }
Пример #15
0
        protected virtual void ShowActiveQuest(Quest quest)
        {
            QuestParameterDelegate backButtonDelegate = null;

            if (activeQuests.Count + offerableQuests.Count >= 2)
            {
                backButtonDelegate = OnQuestBackButton;
                allowBackButton    = true; // May turn in quest and be left with only 1. In this case, still allow back button.
            }
            quest.greeterID = StringField.GetStringValue(playerTextInfo.id);
            QuestMachineMessages.DiscussQuest(player, this, id, quest.id);
            questDialogueUI.ShowActiveQuest(myQuestGiverTextInfo, quest, OnContinueActiveQuest, backButtonDelegate);
            QuestMachineMessages.DiscussedQuest(player, this, id, quest.id);
        }
Пример #16
0
 void IMessageHandler.OnMessage(MessageArgs messageArgs)
 {
     if (!(QuestMachineMessages.IsRequiredID(messageArgs.sender, runtimeSenderID) &&
           QuestMachineMessages.IsRequiredID(messageArgs.target, runtimeTargetID) &&
           IsRequiredValue(messageArgs)))
     {
         return;
     }
     if (QuestMachine.debug)
     {
         Debug.Log("Quest Machine: MessageQuestCondition.OnMessage( " + messageArgs.message + ", " + messageArgs.parameter + ")", quest);
     }
     SetTrue();
 }
Пример #17
0
        /// <summary>
        /// Adds an instance of a quest to a quester's list. If the quest's maxTimes are reached,
        /// deletes the quest from the giver. Otherwise starts cooldown timer until it can be
        /// given again.
        /// </summary>
        /// <param name="quest">Quest to give to quester.</param>
        /// <param name="questerQuestListContainer">Quester's quest list container.</param>
        public virtual void GiveQuestToQuester(Quest quest, QuestListContainer questerQuestListContainer)
        {
            if (quest == null)
            {
                return;
            }
            if (questerQuestListContainer == null)
            {
                Debug.LogWarning("Quest Machine: " + name + ".GiveQuestToQuester - quester (QuestListContainer) is null.", this);
                return;
            }
            var questerTextInfo = new QuestParticipantTextInfo(QuestMachineMessages.GetID(questerQuestListContainer.gameObject), QuestMachineMessages.GetDisplayName(questerQuestListContainer.gameObject), null, null);

            GiveQuestToQuester(quest, questerTextInfo, questerQuestListContainer);
        }
Пример #18
0
        public override void Execute()
        {
            switch (state)
            {
            case ControlState.Start:
                QuestMachineMessages.StartSpawner(spawnerName);
                break;

            case ControlState.Stop:
                QuestMachineMessages.StopSpawner(spawnerName);
                break;

            case ControlState.Despawn:
                QuestMachineMessages.DespawnSpawner(spawnerName);
                break;
            }
        }
Пример #19
0
 public virtual void AbandonQuest(Quest quest)
 {
     if (quest == null || !quest.isAbandonable)
     {
         return;
     }
     if (quest.rememberIfAbandoned)
     {
         quest.SetState(QuestState.Abandoned);
     }
     else
     {
         DeleteQuest(quest.id);
     }
     QuestMachineMessages.QuestAbandoned(this, quest.id);
     if (questJournalUI != null)
     {
         questJournalUI.SelectQuest(null);
     }
     RepaintUIs();
 }
Пример #20
0
 public void SetValue(int newValue, QuestCounterSetValueMode setValueMode = QuestCounterSetValueMode.InformListeners)
 {
     m_currentValue = Mathf.Clamp(newValue, minValue, maxValue);
     if (setValueMode != QuestCounterSetValueMode.DontInformListeners)
     {
         var informDataSync = (updateMode == QuestCounterUpdateMode.DataSync) && (setValueMode != QuestCounterSetValueMode.DontInformDataSync);
         if (informDataSync)
         {
             MessageSystem.SendMessage(this, DataSynchronizer.RequestDataSourceChangeValueMessage, name, currentValue);
         }
         QuestMachineMessages.QuestCounterChanged(this, questID, name, currentValue);
         try
         {
             changed(this);
         }
         catch (Exception e) // Don't let exceptions in user-added events break our code.
         {
             if (Debug.isDebugBuild)
             {
                 Debug.LogException(e);
             }
         }
     }
 }
        public virtual void OnMessage(MessageArgs messageArgs)
        {
            var target = messageArgs.targetString;

            if (!(string.IsNullOrEmpty(target) || string.Equals(target, myID) || StringField.Equals(QuestMachineMessages.GetID(target), myID)))
            {
                return;
            }
            switch (messageArgs.message)
            {
            case QuestMachineMessages.SetIndicatorStateMessage:
                SetIndicatorState(messageArgs.parameter, (QuestIndicatorState)messageArgs.firstValue);
                break;

            case QuestMachineMessages.RefreshIndicatorMessage:
            case QuestMachineMessages.RefreshUIsMessage:
                Repaint();
                break;
            }
        }
Пример #22
0
        /// <summary>
        /// Sets the quest node to a quest state and performs all related activities
        /// such as enabling connections and executing actions. This may cause other
        /// nodes to advance their states, too.
        /// </summary>
        /// <param name="newState">New state.</param>
        public void SetState(QuestNodeState newState, bool informListeners = true)
        {
            if (QuestMachine.debug)
            {
                Debug.Log("Quest Machine: " + ((quest != null) ? quest.GetEditorName() : "Quest") + "." + GetEditorName() + ".SetState(" + newState + ")", quest);
            }

            m_state = newState;

            SetConditionChecking(newState == QuestNodeState.Active);

            if (!informListeners)
            {
                return;
            }

            // Execute state actions:
            var stateInfo = GetStateInfo(m_state);

            if (stateInfo != null && stateInfo.actionList != null)
            {
                for (int i = 0; i < stateInfo.actionList.Count; i++)
                {
                    if (stateInfo.actionList[i] == null)
                    {
                        continue;
                    }
                    stateInfo.actionList[i].Execute();
                }
            }

            // Notify that state changed:
            QuestMachineMessages.QuestNodeStateChanged(this, quest.id, id, m_state);
            try
            {
                stateChanged(this);
            }
            catch (Exception e) // Don't let exceptions in user-added events break our code.
            {
                if (Debug.isDebugBuild)
                {
                    Debug.LogException(e);
                }
            }

            // Handle special node types:
            switch (m_state)
            {
            case QuestNodeState.Active:
                if (nodeType != QuestNodeType.Condition)
                {
                    // Automatically switch non-Condition nodes to True state:
                    SetState(QuestNodeState.True);
                }
                break;

            case QuestNodeState.True:
                // If it's an endpoint, set the overall quest state:
                switch (nodeType)
                {
                case QuestNodeType.Success:
                    if (quest != null)
                    {
                        quest.SetState(QuestState.Successful);
                    }
                    break;

                case QuestNodeType.Failure:
                    if (quest != null)
                    {
                        quest.SetState(QuestState.Failed);
                    }
                    break;
                }
                break;
            }
        }
Пример #23
0
        /// <summary>
        /// Sets the quest state. This may also affect the states of the quest's nodes.
        /// </summary>
        /// <param name="newState">The new quest state.</param>
        public void SetState(QuestState newState, bool informListeners = true)
        {
            if (QuestMachine.debug)
            {
                Debug.Log("Quest Machine: " + GetEditorName() + ".SetState(" + newState + ", informListeners=" + informListeners + ")", this);
            }

            m_state = newState;

            SetStartChecking(newState == QuestState.WaitingToStart);
            SetCounterListeners(newState == QuestState.Active || (newState == QuestState.WaitingToStart && (hasAutostartConditions || hasOfferConditions)));
            if (newState != QuestState.Active)
            {
                StopNodeListeners();
            }

            if (!informListeners)
            {
                return;
            }

            // Execute state actions:
            var stateInfo = GetStateInfo(m_state);

            if (stateInfo != null && stateInfo.actionList != null)
            {
                for (int i = 0; i < stateInfo.actionList.Count; i++)
                {
                    if (stateInfo.actionList[i] != null)
                    {
                        stateInfo.actionList[i].Execute();
                    }
                }
            }

            // Notify that state changed:
            QuestMachineMessages.QuestStateChanged(this, id, m_state);
            try
            {
                stateChanged(this);
            }
            catch (Exception e) // Don't let exceptions in user-added events break our code.
            {
                if (Debug.isDebugBuild)
                {
                    Debug.LogException(e);
                }
            }

            // If going active, activate the start node:
            if (m_state == QuestState.Active && startNode != null)
            {
                startNode.SetState(QuestNodeState.Active);
            }

            // If inactive, clear the indicators:
            if (m_state != QuestState.Active)
            {
                ClearQuestIndicatorStates();
            }

            // If done, set all active nodes to inactive:
            if (m_state == QuestState.Successful || m_state == QuestState.Failed || m_state == QuestState.Abandoned)
            {
                for (int i = 0; i < nodeList.Count; i++)
                {
                    if (nodeList[i].GetState() == QuestNodeState.Active)
                    {
                        nodeList[i].SetState(QuestNodeState.Inactive);
                    }
                }
            }
        }
Пример #24
0
 /// <summary>
 /// Sends a message to the Message System. If the message contains a
 /// colon (:), the part after the colon is sent as the parameter. If
 /// it contains a second colon, the part after the second colon is sent
 /// as a value.
 /// </summary>
 /// <param name="message"></param>
 public void SendToMessageSystem(string message)
 {
     QuestMachineMessages.SendCompositeMessage(this, message);
 }
        public override void ApplyData(string data)
        {
            if (!includeInSavedGameData)
            {
                return;
            }
            if (string.IsNullOrEmpty(data))
            {
                return;
            }

            try
            {
                QuestMachine.isLoadingGame = true;

                var saveData = SaveSystem.Deserialize <SaveData>(data);
                if (saveData == null)
                {
                    return;
                }

                // Clear current quest list:
                DestroyQuestInstances(); // Adds them to deletedStaticQuests, but that's OK since we're going to restore deletedStaticQuests.

                // Restore dynamic quests:
                for (int i = 0; i < saveData.proceduralQuests.Count; i++)
                {
                    try
                    {
                        var questProxy = JsonUtility.FromJson <QuestProxy>(saveData.proceduralQuests[i]);
                        if (questProxy == null)
                        {
                            continue;
                        }
                        var quest = ScriptableObject.CreateInstance <Quest>();
                        quest.name = questProxy.displayName;
                        questProxy.CopyTo(quest);
                        AddQuest(quest);
                    }
                    catch (Exception e)
                    {
                        if (Debug.isDebugBuild)
                        {
                            Debug.LogWarning("Quest Machine: Unable to restore quest from serialized quest proxy. Message: " + e.Message + "\nData: " + saveData.proceduralQuests[i], this);
                        }
                    }
                }

                // Restore list of deleted static quests:
                deletedStaticQuests.Clear();
                deletedStaticQuests.AddRange(saveData.deletedStaticQuests);

                // Restore static quests:
                for (int i = 0; i < Mathf.Min(saveData.staticQuestIds.Count, saveData.staticQuestData.Count); i++)
                {
                    var questID   = saveData.staticQuestIds[i];
                    var questData = saveData.staticQuestData[i];
                    if (string.IsNullOrEmpty(questID) || questData == null || questData.bytes == null)
                    {
                        continue;
                    }
                    if (deletedStaticQuests.Contains(questID))
                    {
                        continue;
                    }
                    var quest = QuestMachine.GetQuestAsset(questID);
                    if (quest == null)
                    {
                        quest = originalQuestList.Find(x => string.Equals(StringField.GetStringValue(x.id), questID));
                    }
                    if (quest == null && Debug.isDebugBuild)
                    {
                        Debug.LogError("Quest Machine: " + name + " Can't find quest " + saveData.staticQuestIds[i] + ". Is it registered with Quest Machine?", this);
                    }
                    if (quest == null)
                    {
                        continue;
                    }
                    quest = quest.Clone();
                    try
                    {
                        QuestStateSerializer.DeserializeInto(quest, questData.bytes, true);
                    }
                    catch (Exception e)
                    {
                        try
                        {
                            if (Debug.isDebugBuild)
                            {
                                Debug.LogWarning("Quest Machine: Unable to restore quest: " + quest.name + ". Message: " + e.Message, this);
                            }
                            Destroy(quest);
                        }
                        catch (Exception) { }
                        quest = quest.Clone();
                    }
                    AddQuest(quest);
                }
                QuestMachineMessages.RefreshIndicator(this, QuestMachineMessages.GetID(this));
            }
            finally
            {
                QuestMachine.isLoadingGame = false;
            }
        }