Page 1 of 1

Custom quest condition not being checked for next quest's node.

Posted: Mon Jul 22, 2024 5:24 pm
by CatStrategist
I have a simple quest with:
1. Start node
2. Condition node
3. Success node

I have applied my custom condition to quest autostart, it works great - starts my quest and transitions to Conditon node.
Now I've applied the same condition to my condition node and it seems to never be checked as if StartChecking() is never run and the quest is stuck in condition node.

My custom condition:

Code: Select all

using System.Collections.Generic;
using PixelCrushers.QuestMachine;
using UnityEngine;

public class ItemCountQuestCondition : QuestCondition {
    public ItemDescription itemType;

    public CounterValueConditionMode comparison = CounterValueConditionMode.AtLeast;

    public QuestNumber requiredValue = new QuestNumber();

    public override string GetEditorName() {
        return "Inventory has " + comparison + " " + requiredValue.GetValue(quest) + " " + itemType;
    }

    public override void StartChecking(System.Action trueAction) {
        base.StartChecking(trueAction);

        if (IsTrue()) {
            SetTrue();
        } else {
            Inventory.ItemAdded += Inventory_OnChange;
            Inventory.ItemRemoved += Inventory_OnChange;
        }
    }

    public override void StopChecking() {
        base.StopChecking();
    }

    private void Inventory_OnChange(Inventory i, InventoryItem item, int quantity) {
        if (IsTrue()) {
            SetTrue();
            Debug.Log("Item count condition is true");
        }
    }

    private bool IsTrue() {
        List<Unit> playersUnits = GameActors.Instance.PlayerActor.units;

        foreach (Unit unit in playersUnits) {
            Inventory inventory = unit.GetInventory();

            if (inventory == null) {
                continue;
            }

            InventoryItem item = inventory.TryGetItem(itemType);

            if (item == null) {
                continue;
            };

            switch (comparison) {
                case CounterValueConditionMode.AtLeast:
                    if (item.quantity >= requiredValue.GetValue(quest)) return true;
                    break;
                case CounterValueConditionMode.AtMost:
                    if (item.quantity <= requiredValue.GetValue(quest)) return true;
                    break;
            }
        }

        return false;
    }
}

Re: Custom quest condition not being checked for next quest's node.

Posted: Mon Jul 22, 2024 9:00 pm
by Tony Li
Hi,

What version of Quest Machine are you using? (Can you back up your project and update to the current version if you're on an older version?)

Are there any errors or warnings in the Console window?

In StopChecking, make sure to unregister from your Inventory.ItemAdded & ItemRemoved events. Otherwise it could cause an error that would prevent subsequently-added handlers (such as your Condition node) from receiving the event.

Consider adding some temporary Debug.Log() lines to your custom condition to log when you hook into and out of Inventory.ItemAdded and ItemRemoved. You can print out quest.id and/or questNode.id with those Debug.Log() lines.

Re: Custom quest condition not being checked for next quest's node.

Posted: Tue Jul 23, 2024 12:24 pm
by CatStrategist
Edit:
I removed and added again a faulty node, configured it the same way and it seems to be working now.
I reverted changes to broken quest state, I am attaching it just in case you are curious what might be broken, maybe it will help you debug and make a fix :)

Anyway, thanks for help, I am good now.


Hello,
- Quest Machine version: 1.2.47, also using Dialogue System version 2.2.47 with integration installed.
- No errors or warnings (with Quest Machine debug turned on)
- Added unsubscribing events to StopChecking()
- Added Debug.Log()s, they seem to be executed correctly for Autostart condition, but not a single log is called for the second condition, StartChecking() is never called.

Logs are called in following order for autostart condition, never for second node:
1. StopChecking()
2. StartChecking(), initializing listeners
3. Once item is picked up, listener is called, setting condition to true
4. StopChecking() is called twice

First StopChecking() stack trace:

Code: Select all

[Pistol] StopChecking()
UnityEngine.Debug:Log (object)
ItemCountQuestCondition:StopChecking () (at Assets/Modules/Quests/ItemCountQuestCondition.cs:32)
PixelCrushers.QuestMachine.QuestCondition:SetTrue () (at Assets/_Assets/Pixel Crushers/Quest Machine/Scripts/Quest/Quest Subasset/Quest Condition/QuestCondition.cs:74)
ItemCountQuestCondition:Inventory_OnChange (Inventory,InventoryItem,int) (at Assets/Modules/Quests/ItemCountQuestCondition.cs:41)
Inventory:InsertItem (ItemDescription,int) (at Assets/Modules/InventorySystem/Inventory.cs:33)
Inventory:AddItem (ItemDescription,int) (at Assets/Modules/InventorySystem/Inventory.cs:21)
InventoryTradeHandler:OnItemClick (Inventory,InventoryItem) (at Assets/Modules/InventorySystem/InventoryHandlers/InventoryTradeHandler.cs:27)
InventoryTradeHandler:<.ctor>b__1_0 (Inventory,InventoryItem) (at Assets/Modules/InventorySystem/InventoryHandlers/InventoryTradeHandler.cs:12)
InventoryUIController:<RenderInventory>b__8_0 (InventoryItem) (at Assets/Modules/InventorySystem/UI/InventoryUIController.cs:41)
ItemUIController:<Init>b__5_0 () (at Assets/Modules/InventorySystem/UI/ItemUIController.cs:24)
UnityEngine.EventSystems.EventSystem:Update () (at ./Library/PackageCache/com.unity.ugui@2.0.0/Runtime/UGUI/EventSystem/EventSystem.cs:530)
Second StopChecking() stack trace:

Code: Select all

[Pistol] StopChecking()
UnityEngine.Debug:Log (object)
ItemCountQuestCondition:StopChecking () (at Assets/Modules/Quests/ItemCountQuestCondition.cs:32)
PixelCrushers.QuestMachine.QuestConditionSet:StopChecking () (at Assets/_Assets/Pixel Crushers/Quest Machine/Scripts/Quest/Quest Condition Set/QuestConditionSet.cs:145)
PixelCrushers.QuestMachine.Quest:SetStartChecking (bool) (at Assets/_Assets/Pixel Crushers/Quest Machine/Scripts/Quest/Quest.cs:826)
PixelCrushers.QuestMachine.Quest:SetState (PixelCrushers.QuestMachine.QuestState,bool) (at Assets/_Assets/Pixel Crushers/Quest Machine/Scripts/Quest/Quest.cs:933)
PixelCrushers.QuestMachine.Quest:Autostart () (at Assets/_Assets/Pixel Crushers/Quest Machine/Scripts/Quest/Quest.cs:840)
PixelCrushers.QuestMachine.QuestConditionSet:SetTrue () (at Assets/_Assets/Pixel Crushers/Quest Machine/Scripts/Quest/Quest Condition Set/QuestConditionSet.cs:195)
PixelCrushers.QuestMachine.QuestConditionSet:OnTrueCondition () (at Assets/_Assets/Pixel Crushers/Quest Machine/Scripts/Quest/Quest Condition Set/QuestConditionSet.cs:190)
PixelCrushers.QuestMachine.QuestCondition:SetTrue () (at Assets/_Assets/Pixel Crushers/Quest Machine/Scripts/Quest/Quest Subasset/Quest Condition/QuestCondition.cs:75)
ItemCountQuestCondition:Inventory_OnChange (Inventory,InventoryItem,int) (at Assets/Modules/Quests/ItemCountQuestCondition.cs:41)
Inventory:InsertItem (ItemDescription,int) (at Assets/Modules/InventorySystem/Inventory.cs:33)
Inventory:AddItem (ItemDescription,int) (at Assets/Modules/InventorySystem/Inventory.cs:21)
InventoryTradeHandler:OnItemClick (Inventory,InventoryItem) (at Assets/Modules/InventorySystem/InventoryHandlers/InventoryTradeHandler.cs:27)
InventoryTradeHandler:<.ctor>b__1_0 (Inventory,InventoryItem) (at Assets/Modules/InventorySystem/InventoryHandlers/InventoryTradeHandler.cs:12)
InventoryUIController:<RenderInventory>b__8_0 (InventoryItem) (at Assets/Modules/InventorySystem/UI/InventoryUIController.cs:41)
ItemUIController:<Init>b__5_0 () (at Assets/Modules/InventorySystem/UI/ItemUIController.cs:24)
UnityEngine.EventSystems.EventSystem:Update () (at ./Library/PackageCache/com.unity.ugui@2.0.0/Runtime/UGUI/EventSystem/EventSystem.cs:530)
Update condition code:

Code: Select all

using System.Collections.Generic;
using PixelCrushers.QuestMachine;
using UnityEngine;

public class ItemCountQuestCondition : QuestCondition {
    public ItemDescription itemType;

    public CounterValueConditionMode comparison = CounterValueConditionMode.AtLeast;

    public QuestNumber requiredValue = new QuestNumber();

    public override string GetEditorName() {
        return "Inventory has " + comparison + " " + requiredValue.GetValue(quest) + " " + itemType;
    }

    public override void StartChecking(System.Action trueAction) {
        Debug.Log($"[{itemType.itemName}] StartChecking() - Start ");		# <-------- ADDED

        base.StartChecking(trueAction);

        if (IsTrue()) {
            Debug.Log($"[{itemType.itemName}] StartChecking() - True at start.");		# <-------- ADDED
            SetTrue();
        } else {
            Debug.Log($"[{itemType.itemName}] StartChecking() - False at start, subscribing listeners.");
            Inventory.ItemAdded += Inventory_OnChange;
            Inventory.ItemRemoved += Inventory_OnChange;
        }
    }

    public override void StopChecking() {
        Debug.Log($"[{itemType.itemName}] StopChecking()")		# <-------- ADDED
        base.StopChecking();
        Inventory.ItemAdded -= Inventory_OnChange;		# <-------- ADDED
        Inventory.ItemRemoved -= Inventory_OnChange;		# <-------- ADDED
    }

    private void Inventory_OnChange(Inventory i, InventoryItem item, int quantity) {
        if (IsTrue()) {
            Debug.Log($"[{itemType.itemName}] Inventory_OnChange - Condition true.");		# <-------- ADDED
            SetTrue();
            Debug.Log("Item count condition is true");		# <-------- ADDED
        }
    }

    private bool IsTrue() {
        List<Unit> playersUnits = GameActors.Instance.PlayerActor.units;

        foreach (Unit unit in playersUnits) {
            Inventory inventory = unit.GetInventory();

            if (inventory == null) {
                continue;
            }

            InventoryItem item = inventory.TryGetItem(itemType);

            if (item == null) {
                continue;
            };

            switch (comparison) {
                case CounterValueConditionMode.AtLeast:
                    if (item.quantity >= requiredValue.GetValue(quest)) return true;
                    break;
                case CounterValueConditionMode.AtMost:
                    if (item.quantity <= requiredValue.GetValue(quest)) return true;
                    break;
            }
        }

        return false;
    }
}

Re: Custom quest condition not being checked for next quest's node.

Posted: Tue Jul 23, 2024 8:45 pm
by Tony Li
Hi,

I'm glad you got it all working. If any questions come up, feel free to follow up.