Custom Quest Reward Handler

v4.0

When using the ItemObjectReward type, you will need to determine how the items created are handled. This is entirely dependent on your inventory system, which is likely different from other developers systems.

View the Quest Repository - Party Based RPG Variant object in the world scene of the Party Based RPG demo game. This has an additional class: QuestRewardHandler

Quest Reward Handler

ItemObjectReward.cs

The GiveReward() method on ItemObjectReward calls HandleItemObjectReward() on the questRepository.

// ItemObjectReward.cs

public override void GiveReward(IUseGameModules owner)
{
    var generatedItems = new GameItemObjectList();
    foreach (var lootBox in lootBoxes)
        generatedItems.list.AddRange(lootBox.GenerateLoot().list);
    
    // Pass the items to the Handler on the quest Repository -- this is something you'll need to create for
    // your game!!
    questRepository.HandleItemObjectReward(generatedItems);
}

QuestRepository.cs

QuestRepository has a IHandleQuestRewards variable. This is populated at start, if you have another class on the object that implements IHandleQuestRewards.

If so, when HandleItemObjectReward() is called, the custom reward handler is used: HandleItemObjectReward() with the GameItemObjectList with all of the items that need to be handled attached.

Your custom reward handler just has to iterate through the GameItemObjectList and do something to each item. That is probably something you've already figured out how to do for your inventory system 😀

// QuestRepository.cs

private IHandleQuestRewards _customQuestRewardHandler;

// ...

private void Start() => SaveQuestRewardHandler();

private void SaveQuestRewardHandler()
{
    _customQuestRewardHandler = GetComponent<IHandleQuestRewards>();
    if (_customQuestRewardHandler != null)
    {
        WriteToConsole($"IHandleQuestRewards has been populated."
            , "QuestRepository", writeToConsoleColor, writeToConsole, false, gameObject);
        return;
    }

    WriteToConsole($"Custom IHandleQuestRewards class not found. This can be ignored if you do not " +
        $"have any Quest Rewards that require custom handling, such as Item Object rewards. Otherwise, " +
        $"you should create a custom class which implements IHandleQuestRewards and write code to " +
        $"handle the rewards that may be created. Add that script to the QuestRepository object."
        , "QuestRepository", writeToConsoleColor, writeToConsole, true, gameObject);
}

// ...
        
public void HandleItemObjectReward(GameItemObjectList gameItemObjectList)
{
    if (_customQuestRewardHandler == null)
    {
        WriteToConsole($"HandleItemObjectReward() has been called, but there is no IHandleQuestReward " +
                       $"handler attached to the QuestRepository object!"
            , "QuestRepository", writeToConsoleColor, writeToConsole, true, gameObject);
        return;
    }
    
    _customQuestRewardHandler.HandleItemObjectReward(gameItemObjectList);
}

QuestRewardHandler (IHandleQuestRewards)

You can name your handler something different, if you'd like, but it must be a Monobehaviour which implements IHandleQuestRewards.

In the class from the Party Based RPG demo game, we start a Coroutine to handle the items one by one. This demo uses the Game Modules Inventory System, and each ItemObject that is spawned will be shown as a "Held Item" on the screen, following the mouse position.

The player can choose to click the world to "Drop" the item into it, or select a player portrait by clicking the portrait or typing "1", "2", "3", or "4". If the player inventory can hold the item, it will be placed there.

After one of those actions occurs, the coroutine will move to the next item in the list, until there is no more.

public class QuestRewardHandler : MonoBehaviour, IHandleQuestRewards
{
    private int _index = 0;

    public void HandleItemObjectReward(GameItemObjectList gameItemObjectList) 
            => StartCoroutine(GiveOutItems(gameItemObjectList));

    private IEnumerator GiveOutItems(GameItemObjectList gameItemObjectList)
    {
        _index = 0; // Reset the index
        
        // Do this for each item in the list
        while (_index < gameItemObjectList.Count())
        {
            // Yield while onScreenItem is held -- wait for the player to do something with the current object first.
            while (onScreenItem.ItemIsHeld)
                yield return null;

            onScreenItem.Pickup(gameItemObjectList.list[_index]);
            _index += 1;
        }
    }
}

If you're using the Game Modules Inventory System, then feel free to use this QuestRewardHandler for your project as well. Otherwise, you'll need to write your own.

Hopefully you've realized that it's not that challenging to create your own handler!

Last updated