Or, how to make players do things in your game
In this article I would like to share my experience building quest / tutorial systems for simulation games. It will consist of a theoretical and slightly more practical part based on developing quests with ECS (and reactive systems). Without further ado let’s start with the theoretical part.
In games, quests are tasks, which player can accomplish in order to get further in the game and receive some kind of a reward. Tutorials can be seen as mandatory quests. A quest can contain a list of single tasks, but for simplicity I would like to define, that there is only one task per quest.
Tasks are normally defined by game designers and are described through unlocking requirement, goals or completion requirements and rewards. In some cases it is good to provide task cancelation requirements. But before I go in depth on the ingredients of different requirements, let me first list all possible states of a task:
- pending — the task did not met the unlocking requirement yet
- unlocked — the unlocking requirements are met, but it is not in progress yet, maybe because of the limit of possible tasks in progress
- in progress — the task was unlocked and shown to the player. It might be useful to have a sub-state, or a separate state for new task. This symbols that the task is technically in progress, but player did not read the objections yet. I did not give it a separate state because it is UI specific
- completed — task was in progress and player did everything necessary to complete it. Now it is time to collect the reward. If there is no reward the task might directly switch to the next state. There are also systems where quests autocomplete
- done — task was completed and user collected the reward
- canceled — this state is important if you want a quest to disappear. It’s particularly useful, if you introduce a new quests which player, who advanced beyond a certain threshold, shall not see
Now it is time to speak about different requirements.
Those are mainly based on game state / player progress. The simplest requirement is level or XP, but it is also very common to chain unlocking of the quest to a resource or a certain interaction.
Say you want to teach a player to do crafting. When a player accumulates the right resources, we should unlock a quest where the player needs to use those resources for crafting. Same can apply to building, upgrading, training etc… Even using some distant, or just unlocked parts of the UI may be designed as a quest, with unlocking requirements of this UI element appearing.
Another unlocking requirement which I find very useful is completion of another task. Task A unlocks only when task B and C are done. This way we control the flow of the quests, linearising the order quests are presented in.
As mentioned in the canceled state description, it is very important to avoid some basic quests when the player is too advanced. If you introduce a quest for beginners you will set unlocking requirements in a way that advanced player will also met. However you don’t want advanced players to do basic tasks.
In my opinion the simplest thing is to couple cancelation to an XP of some sort, or on a completion of another task.
There are mainly two requirement categories for completion:
- Game state based
- Ad-hoc actions
For example we are building a farming game and we have a quest based on apples. In Game state based category we define that the quest is completed, when the player have 2000 apples. If apples is a consumable resource the player would have to stop consuming it and keep harvesting apples till s/he has 2000 of it.
In the Ad-hoc actions category, we would define that player should harvest 2000 apples after the task moved to “in progress” state. This way we do not impose any consumption restriction on the player and don’t care about previous achievements. Btw. quests with Game state based completion requirements can be auto-completed. Player might already reached the state needed for completion. However the Ad-hoc actions based, always needs to be worked on.
A task/quest without reward is a little bit disappointing, specially if a quest involves some grinding. The simplest solution is to give players XP, but sometimes completion of a quest can be used to give a player some rare items, or random GATCHA.
As mentioned before quests are defined by game designers, they are tools to steer players in to desirable direction. However there is only so much stuff a game designer can come up with. If your quest system is well-formed, you might try to procedurally generate them. From my experience, this is actually one of the last tasks a game production team gets to do before automation mode.
How do I implement a quest system with ECS
In my article Games Data and Entitas I argue that data can be divided into three categories:
- Game State
- Runtime Data
In case of quests, we need to use all three of those categories. The definition of the quest is stored as a configuration. In progress, Done and canceled quests are stored as game state.
At game initialisation, we would go through the configuration and create a set of “pending” and “in progress” quests, according to quests already persisted in the game state. We also check if we can store new quests as canceled.
At runtime we need a set of reactive systems, which will monitor the relevant parts of the game state and transform pending quests to unlocked and if possible to in progress. Quests based on ad-hoc actions, will have components storing the progress.
We need another set of reactive systems, which monitor the game state and user interactions in order complete a quest, or at least change quest progress in case of ad-hoc actions.
When a quest moves to done, it will be persisted in the game state.
This is basically the magic sauce. The details can become a bit more involved, but in my opinion, ECS is a very quest friendly architecture. Specifically if you are following it strictly and turn every player event to a component.
BTW. writing reactive systems for procedural generated quests is not a rocket science.